Разница между сложить и уменьшить?
пытаясь узнать F#, но запутался при попытке различить раза и уменьшить. Раза, кажется, делает то же самое, но принимает дополнительный параметр. Есть ли законная причина для существования этих двух функций или они существуют для размещения людей с разным происхождением? (Например: строка и строка в C#)
вот фрагмент кода, скопированный из примера:
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])
4 ответа:
Fold
принимает явное начальное значение аккумулятора, в то время какreduce
использует первый элемент входного списка в качестве начального значения агрегатной.это означает, что аккумулятор и, следовательно, тип результата должны соответствовать типу элемента списка, тогда как они могут отличаться в
fold
как аккумулятор предоставляется отдельно. Это отражается в типах:List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State List.reduce : ('T -> 'T -> 'T) -> 'T list -> 'T
reduce
вызывает исключение в пустом списке ввода.
в дополнение к тому, что сказал ли, вы можете определить
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)
давайте посмотрим на их подписи:
> List.reduce;; val it : (('a -> 'a -> 'a) -> 'a list -> 'a) = <fun:clo@1> > List.fold;; val it : (('a -> 'b -> 'a) -> 'a -> 'b list -> 'a) = <fun:clo@2-1>
есть некоторые важные различия:
- пока
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
fold
это гораздо более ценная функция, чемreduce
. Вы можете определить много различных функций в терминахfold
.
reduce
- это просто подмножествоfold
.определение створка:
let rec fold f v xs = match xs with | [] -> v | (x::xs) -> f (x) (fold f v xs )
примеры функций, определенных в терминах fold:
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