F#中List.Fold和List.Foldback的简单说明

时间:2018-11-02 16:15:51

标签: f# f#-interactive f#-data f#-3.0

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

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

1 个答案:

答案 0 :(得分:3)

理解它的最好方法是举一个例子。假设您有一个数字列表,而您想找出总数。在命令式编程中,您可以执行以下操作:

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

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

printfn "%A" total   // 133

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

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

瞧!如果斜视,则可以在两个解决方案中识别相同的元素。

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

让我们看看List.fold的签名:

val List.fold: 
   folder: 'State -> 'T -> 'State ->
   state : 'State  ->
   list  : 'T list 
        -> 'State

看看元素如何匹配?

List.foldBack是相同的,但元素是按相反顺序进给的。参数的顺序也不同。


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

如果您没有List.fold,并且想实现一个totalF函数而又不可变,那么您将如何做呢?您将需要递归,最好是尾递归:

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

numbers
|> totalF 0
|> printfn "%A"    // 133

同样,您可以像以前一样查看所有元素。实际上,如果我们将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

您得到fold,签名和使用方式相同:

val totalF: 
   f    : 'a -> 'b -> 'a ->
   total: 'a             ->
   ns   : 'b list        
       -> 'a