Mencoba mempelajari F # tetapi bingung ketika mencoba membedakan antara lipat dan kurangi . Lipat tampaknya melakukan hal yang sama tetapi membutuhkan parameter tambahan. Adakah alasan yang sah mengapa kedua fungsi ini ada atau ada untuk mengakomodasi orang-orang dengan latar belakang yang berbeda? (Misalnya: String dan string di C #)
Berikut cuplikan kode yang disalin dari contoh:
let sumAList list =
List.reduce (fun acc elem -> acc + elem) list
let sumAFoldingList list =
List.fold (fun acc elem -> acc + elem) 0 list
printfn "Are these two the same? %A "
(sumAList [2; 4; 10] = sumAFoldingList [2; 4; 10])
f#
functional-programming
reduce
fold
Wallace
sumber
sumber
fold f a l
dapat ditulis sebagaireduce f a::l
.fold
dalam istilahreduce
lebih rumit dari itu - jenis akumulatorfold
tidak harus sama dengan jenis benda dalam daftar!Jawaban:
Fold
mengambil nilai awal eksplisit untuk akumulator sementarareduce
menggunakan elemen pertama dari daftar input sebagai nilai akumulator awal.Artinya, akumulator dan oleh karena itu jenis hasil harus cocok dengan jenis elemen daftar, sedangkan
fold
akumulator dapat berbeda karena akumulator disediakan secara terpisah. Ini tercermin dalam jenis:Selain
reduce
melontarkan pengecualian pada daftar masukan kosong.sumber
fold
, Anda cukup menambahkan nilai awal itu ke awal daftar dan lakukanreduce
? Lalu apa gunanyafold
?'state -> 'a -> 'state
untuk lipatan vs'a -> 'a -> 'a
untuk mengurangi, jadi pengurangan membatasi jenis hasil agar sama dengan jenis elemen. Lihat jawaban Tomas Petricek di bawah ini.Selain apa yang Lee katakan, Anda dapat mendefinisikan
reduce
dalam istilahfold
, tetapi tidak (dengan mudah) sebaliknya:Fakta yang
fold
mengambil nilai awal eksplisit untuk akumulator juga berarti bahwa hasil darifold
fungsi dapat memiliki tipe yang berbeda dari tipe nilai dalam daftar. Misalnya, Anda dapat menggunakan akumulator tipestring
untuk menggabungkan semua angka dalam daftar menjadi representasi tekstual:Saat menggunakan
reduce
, jenis akumulator sama dengan jenis nilai dalam daftar - ini berarti bahwa jika Anda memiliki daftar angka, hasilnya harus berupa angka. Untuk menerapkan contoh sebelumnya, Anda harus mengonversi angkanya menjadi yangstring
pertama lalu mengakumulasikan:sumber
fold' & its ability to express
pengurangan '. Beberapa bahasa memiliki konsep chirality struktural (Haskell, saya sedang melihat Anda), Anda dapat melipat ke kiri atau ke kanan yang digambarkan secara visual di wiki ini ( en.wikipedia.org/wiki/Fold_%28higher-order_function ). Dengan konstruksi identitas, dua operator FP 'fundamental' lainnya (filter dan fmap) juga dapat diimplementasikan dengan konstruksi bahasa kelas satu `lipat 'yang ada (semuanya adalah konstruksi isomorfik). ( cs.nott.ac.uk/~pszgmh/fold.pdf ) Lihat: HoTT, Princeton (Bagian komentar ini terlalu kecil untuk diisi ..)Mari kita lihat tanda tangan mereka:
Ada beberapa perbedaan penting:
reduce
bekerja pada satu jenis elemen saja, elemen akumulator dan list difold
dapat memiliki tipe yang berbeda.Dengan
reduce
, Anda menerapkan fungsif
ke setiap elemen daftar mulai dari yang pertama:f (... (f i0 i1) i2 ...) iN
.Dengan
fold
, Anda melamarf
mulai dari akumulators
:f (... (f s i0) i1 ...) iN
.Oleh karena itu,
reduce
menghasilkanArgumentException
daftar kosong. Selain itu,fold
lebih umum darireduce
; dapat Anda gunakanfold
untuk menerapkanreduce
dengan mudah.Dalam beberapa kasus, penggunaan
reduce
lebih ringkas:atau lebih nyaman jika tidak ada akumulator yang masuk akal:
Secara umum,
fold
lebih kuat dengan akumulator tipe arbitrer:sumber
fold
adalah fungsi yang jauh lebih berharga daripadareduce
. Anda dapat mendefinisikan berbagai fungsi dalam istilahfold
.reduce
hanyalah sebagian darifold
.Definisi lipatan:
Contoh fungsi yang didefinisikan dalam istilah lipatan:
sumber
fold
berbeda dariList.fold
sebagai jenisList.fold
yaitu('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
kasus, tetapi dalam Anda('a -> 'b -> 'b) -> 'b -> 'a list -> 'b
. Hanya untuk membuatnya eksplisit. Selain itu, penerapan append Anda salah. Ini akan berfungsi jika Anda menambahkan pengikatan padanya, misalnyaList.collect id (fold (fun x y -> x :: y) [] [xs;ys])
, atau mengganti kontra dengan operator tambahan. Jadi, append bukanlah contoh terbaik dalam daftar ini.