F#中List.Fold和List.Foldback的简单解释

T.M*_*T.M 1 f# f#-interactive f#-3.0 f#-data

任何人都可以用非常简单的方式解释 F# 中的 List.Fold 和 List.Foldback 是什么。我读了几本书,并试图在网上搜索一个简单的解释,但我仍然不明白。

- 这不是一个重复的问题,也没有在另一个链接中回答。

AMi*_*res 7

理解它的最好方法是通过一个例子。想象一下,你有一个数字列表,你想找出总数。在命令式编程中,您可以这样做:

let numbers = [ 19 ; 52 ; 35 ; 27]

let mutable total = 0
for n in numbers do
    total <- total + n

printfn "%A" total   // 133
Run Code Online (Sandbox Code Playgroud)

这是一个很好的解决方案,但不起作用。让我们List.fold来做同样的事情:

numbers
|> List.fold (fun total n -> total + n) 0
|> printfn "%A"    // 133
Run Code Online (Sandbox Code Playgroud)

瞧!如果你眯着眼睛,你可以在两种解决方案中识别出相同的元素。

  • 您的国家: total
  • 您的文件夹操作采用先前状态和列表元素并返回新状态: total + n
  • 您的初始值: 0

让我们看看 的签名List.fold

val List.fold: 
   folder: 'State -> 'T -> 'State ->
   state : 'State  ->
   list  : 'T list 
        -> 'State
Run Code Online (Sandbox Code Playgroud)

看看元素是如何匹配的?

List.foldBack是相同的,但元素以相反的顺序馈送。参数的顺序也不同。


有趣的事情之一fold是,在许多情况下,它可以代替尾递归函数:

如果你没有List.fold并且想实现一个totalF没有 mutable的函数,你会怎么做?你需要递归,更好的是尾递归:

let rec totalF total ns =
    match ns with
    | []        ->         total
    | n :: tail -> totalF (total + n) tail

numbers
|> totalF 0
|> printfn "%A"    // 133
Run Code Online (Sandbox Code Playgroud)

同样,您可以像以前一样看到所有元素。事实上,如果我们做成total + n一个参数totalF

let rec totalF f total ns =
    match ns with
    | []        -> total
    | n :: tail -> totalF f (f total n) tail

numbers
|> totalF (fun total n -> total + n) 0
|> printfn "%A"    // 133
Run Code Online (Sandbox Code Playgroud)

你得到fold,签名和使用是一样的:

val totalF: 
   f    : 'a -> 'b -> 'a ->
   total: 'a             ->
   ns   : 'b list        
       -> 'a
Run Code Online (Sandbox Code Playgroud)