Разница между сбросом и уменьшением?
Попытка узнать F #, но запуталась, пытаясь отличить fold и уменьшить. Fold, похоже, делает то же самое, но принимает дополнительный параметр. Существует ли законная причина для существования этих двух функций или они предназначены для размещения людей с разным опытом? (Например: String и строка в С#)
Вот фрагмент кода, скопированный из образца:
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])
Ответы
Ответ 1
Fold
принимает явное начальное значение для аккумулятора, а reduce
использует первый элемент списка ввода как начальное значение аккумулятора.
Это означает, что аккумулятор и, следовательно, тип результата должны совпадать с типом элемента списка, тогда как они могут отличаться в Fold
, поскольку накопитель предоставляется отдельно. Это отражается в типах:
List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State
List.reduce : ('T -> 'T -> 'T) -> 'T list -> 'T
Кроме того, reduce
генерирует исключение в пустом списке.
Ответ 2
В дополнение к тому, что сказал Ли, вы можете определить reduce
в терминах fold
, но не (легко) наоборот:
let reduce f list =
match list with
| head::tail -> List.fold f head tail
| [] -> failwith "The list was empty!"
Тот факт, что fold
принимает явное начальное значение для аккумулятора, также означает, что результат функции fold
может иметь другой тип, чем тип значений в списке. Например, вы можете использовать накопитель типа string
, чтобы объединить все числа в списке в текстовое представление:
[1 .. 10] |> List.fold (fun str n -> str + "," + (string n)) ""
При использовании reduce
тип аккумулятора совпадает с типом значений в списке - это означает, что если у вас есть список чисел, результат должен быть числом. Чтобы реализовать предыдущий образец, вам нужно сначала преобразовать числа в string
, а затем скопировать:
[1 .. 10] |> List.map string
|> List.reduce (fun s1 s2 -> s1 + "," + s2)
Ответ 3
Посмотрите на их подписи:
> List.reduce;;
val it : (('a -> 'a -> 'a) -> 'a list -> 'a) = <fun:[email protected]>
> List.fold;;
val it : (('a -> 'b -> 'a) -> 'a -> 'b list -> 'a) = <fun:[email protected]>
Есть несколько важных отличий:
- Пока
reduce
работает только с одним типом элементов, элементы аккумулятора и списка в fold
могут быть в разных типах.
-
С помощью reduce
вы применяете функцию f
к каждому элементу списка, начиная с первого:
f (... (f i0 i1) i2 ...) iN
.
С помощью fold
вы применяете f
, начиная с аккумулятора s
:
f (... (f s i0) i1 ...) iN
.
Следовательно, reduce
приводит к ArgumentException
в пустом списке. Более того, fold
более общий, чем reduce
; вы можете использовать fold
для простого reduce
.
В некоторых случаях использование reduce
более кратким:
// Return the last element in the list
let last xs = List.reduce (fun _ x -> x) xs
или более удобно, если нет разумного аккумулятора:
// Intersect a list of sets altogether
let intersectMany xss = List.reduce (fun acc xs -> Set.intersect acc xs) xss
В общем случае fold
более мощный с аккумулятором произвольного типа:
// Reverse a list using an empty list as the accumulator
let rev xs = List.fold (fun acc x -> x::acc) [] xs
Ответ 4
fold
является гораздо более ценной функцией, чем reduce
. Вы можете определить множество различных функций в терминах fold
.
reduce
является всего лишь подмножеством fold
.
Определение складки:
let rec fold f v xs =
match xs with
| [] -> v
| (x::xs) -> f (x) (fold f v xs )
Примеры функций, определенных в терминах складки:
let sum xs = fold (fun x y -> x + y) 0 xs
let product xs = fold (fun x y -> x * y) 1 xs
let length xs = fold (fun _ y -> 1 + y) 0 xs
let all p xs = fold (fun x y -> (p x) && y) true xs
let reverse xs = fold (fun x y -> y @ [x]) [] xs
let map f xs = fold (fun x y -> f x :: y) [] xs
let append xs ys = fold (fun x y -> x :: y) [] [xs;ys]
let any p xs = fold (fun x y -> (p x) || y) false xs
let filter p xs =
let func x y =
match (p x) with
| true -> x::y
| _ -> y
fold func [] xs