折叠与缩小之间的区别?

试图学习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。 例如,可以使用stringtypes的累加器将列表中的所有数字连接成文本表示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