折叠与缩小之间的区别?
试图学习F#,但试图区分折叠和缩小时感到困惑。 折叠似乎做同样的事情,但需要一个额外的参数。 这两个function是否存在合法的原因,或者是否有适应不同背景的人的需要? (例如:C#中的string和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])
Fold
需要一个明确的累加器初始值,而reduce
使用input列表的第一个元素作为初始累加器值。
这意味着累加器,因此结果types必须与列表元素types匹配,而累加器是单独提供的,它们可以有所不同。 这体现在:
List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State List.reduce : ('T -> 'T -> 'T) -> 'T list -> 'T
另外reduce
会在空的input列表中抛出一个exception。
除了Lee所说的,你可以定义fold
reduce
,但是不能(反过来)相反:
let reduce f list = match list with | head::tail -> List.fold f head tail | [] -> failwith "The list was empty!"
fold
为累加器带来一个明确的初始值的事实也意味着fold
函数的结果可能与列表中的值的types具有不同的types。 例如,可以使用string
types的累加器将列表中的所有数字连接成文本表示forms:
[1 .. 10] |> List.fold (fun str n -> str + "," + (string n)) ""
使用reduce
,累加器的types与列表中的值的types相同 – 这意味着如果您有一个数字列表,结果必须是一个数字。 要实现前面的示例,您必须首先将数字转换为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
适用于一种types的元素,但fold
的累加器和列表元素可以是不同的types。 -
使用
reduce
,将函数f
应用于从第一个列表开始的每个列表元素:f (... (f i0 i1) i2 ...) iN
。有了
fold
,你可以从累加器开始应用f
:f (... (fs i0) i1 ...) iN
。
因此,在空列表中reduce
ArgumentException
结果。 而且, fold
比generics更通用。 您可以使用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
一般来说,在任意types的累加器中, fold
是更强大的:
// Reverse a list using an empty list as the accumulator let rev xs = List.fold (fun acc x -> x::acc) [] xs
fold
是一个比reduce
更有价值的function。 您可以根据fold
定义许多不同的function。
reduce
只是fold
一个子集。
折叠的定义:
let rec fold fv xs = match xs with | [] -> v | (x::xs) -> f (x) (fold fv xs )
按折叠定义的函数示例:
let sum xs = fold (fun xy -> x + y) 0 xs let product xs = fold (fun xy -> x * y) 1 xs let length xs = fold (fun _ y -> 1 + y) 0 xs let all p xs = fold (fun xy -> (px) && y) true xs let reverse xs = fold (fun xy -> y @ [x]) [] xs let map f xs = fold (fun xy -> fx :: y) [] xs let append xs ys = fold (fun xy -> x :: y) [] [xs;ys] let any p xs = fold (fun xy -> (px) || y) false xs let filter p xs = let func xy = match (px) with | true -> x::y | _ -> y fold func [] xs