Wal*_*ace 115 reduce f# functional-programming fold
试图学习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])
Run Code Online (Sandbox Code Playgroud)
Tom*_*cek 178
除了什么李先生说,你可以定义reduce
来讲fold
,而不是(容易)倒过来:
let reduce f list =
match list with
| head::tail -> List.fold f head tail
| [] -> failwith "The list was empty!"
Run Code Online (Sandbox Code Playgroud)
fold
对累加器采用显式初始值的事实也意味着fold
函数的结果可以具有与列表中的值类型不同的类型.例如,您可以使用类型的累加器string
将列表中的所有数字连接成文本表示:
[1 .. 10] |> List.fold (fun str n -> str + "," + (string n)) ""
Run Code Online (Sandbox Code Playgroud)
使用时reduce
,累加器的类型与列表中的值类型相同 - 这意味着如果您有数字列表,则结果必须是数字.要实现上一个示例,您必须string
先将数字转换为第一个然后累积:
[1 .. 10] |> List.map string
|> List.reduce (fun s1 s2 -> s1 + "," + s2)
Run Code Online (Sandbox Code Playgroud)
Lee*_*Lee 164
Fold
在reduce
使用输入列表的第一个元素作为初始累加器值时,为累加器采用显式初始值.
这意味着累加器和结果类型必须与列表元素类型匹配,而它们可以不同,fold
因为累加器是单独提供的.这反映在以下类型中:
List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State
List.reduce : ('T -> 'T -> 'T) -> 'T list -> 'T
Run Code Online (Sandbox Code Playgroud)
另外reduce
在空输入列表上抛出异常.
pad*_*pad 19
我们来看看他们的签名:
> 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>
Run Code Online (Sandbox Code Playgroud)
有一些重要的区别:
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
Run Code Online (Sandbox Code Playgroud)
如果没有合理的累加器,或者更方便:
// Intersect a list of sets altogether
let intersectMany xss = List.reduce (fun acc xs -> Set.intersect acc xs) xss
Run Code Online (Sandbox Code Playgroud)
通常,fold
使用任意类型的累加器更强大:
// Reverse a list using an empty list as the accumulator
let rev xs = List.fold (fun acc x -> x::acc) [] xs
Run Code Online (Sandbox Code Playgroud)
Raz*_*dze 16
fold
是一个比它更有价值的功能reduce
.您可以根据需要定义许多不同的功能fold
.
reduce
只是一个子集fold
.
折叠的定义:
let rec fold f v xs =
match xs with
| [] -> v
| (x::xs) -> f (x) (fold f v xs )
Run Code Online (Sandbox Code Playgroud)
以折叠方式定义的函数示例:
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
Run Code Online (Sandbox Code Playgroud)