let rec aggregateList (f:int->int->int) init list =
match list with
| [] -> init
| hd::tl ->
let rem = aggregateList f init tl
f rem hd
let add a b = a + b
let mul a b = a * b
//to use in F# Interactive:
//aggregateList add 0 [1..5];;
来自Thomas Petricek的“真实世界的功能编程”中的这个例子
我在第二个分支中不了解该模式匹配: f rem hd 。 有人能帮助我吗?
答案 0 :(得分:4)
让我们先分解aggregateList
函数声明。该函数有三个参数:
int
并返回第三个int
。然后,该函数将其提供的列表与两种可能性之一匹配:
init
。hd
(或头部)以及列表的其余部分,并将其分配给tl
(或尾部)。然后它执行递归调用aggregateList f init tl
。返回时,它会获取结果并将其分配给rem
。然后,它会在f
和rem
上调用hd
。正如其他人所指出的,这与List.foldback
function in the basic F# library。
当然要小心选择init
值,因为如果您执行了aggregateList mul 0 somelist;;
,无论您提供哪个列表,都只会获得0
。
答案 1 :(得分:1)
它调用函数f(其中一个参数),给出递归调用的结果和下一个项目。
rem
是余数,或者在这种情况下是剩余值的结果。
hd
是下一个项目,如模式匹配的| hd::tl ->
部分所示。
实际上,这个聚合函数需要一个函数,一个起点和一个列表。表示示例行的方法是:
(1 + (2 + (3 + (4 + (5 + 0)))))
答案 2 :(得分:1)
为了好玩,让我们做一些printf
样式调试:
> aggregateList (fun acc x -> printf "%i " x; acc + x) 0 [1..10];;
10 9 8 7 6 5 4 3 2 1 val it : int = 55
看起来该函数等同于List.foldBack
(或其他语言中的fold_right
):它从右到左遍历列表中的每个项目并在它们上调用函数f
让我们以几种不同的方式重写函数:
// functional version
let rec foldBack f seed = function
| [] -> seed
| x::xs -> let res = foldBack f seed xs in f res x
// imperative version
let foldBack f seed xs =
let mutable result = seed
for x in List.rev xs do
result <- f result x
result
// C# equivalent
public static U FoldBack<T, U>(Func<T, U> f, U seed, IEnumerable<T> xs) {
foreach(T x in xs.Reverse())
seed = f(seed, x);
return seed;
}
你可以使用这样的功能:
let sum = foldBack (+) 0 [1..10] // returns 55
let sumOfSquares = foldBack (fun acc x -> acc + x * x) 0 [1..10];; // 385
我在第二个分支中不明白 模式匹配:f rem hd。可以 有人帮帮我吗?
让我们从我们已经了解的F#函数开始:
f
是一个类型为int -> int -> int
的函数。你传递函数就好像它们是任何其他变量,如整数或字符串。f rem hd
使用两个参数f
和rem
调用函数hd
。回到原来的功能:
let rec aggregateList (f:int->int->int) init list =
match list with
| [] -> init
| hd::tl ->
let rem = aggregateList f init tl // 1
f rem hd // 2
在第1行中,我们使用aggregateList
重复调用tl
。由于列表越来越小,我们最终会遇到nil的情况,返回init
。
在第2行中,f rem hd
是函数的返回值。但是,由于我们在向列表末尾移动时向下移动堆栈,因此当我们向上走回堆栈跟踪时,我们将为每个元素调用此函数(按从右到左的顺序)。 / p>
给定aggregateList (+) 0 [1..10]
,nil大小写返回0
,因此我们调用:
列表中没有其他项目,因此整个函数返回55
。
可以想象,aggregateList
中的嵌套调用会像这样评估长度为n
的列表:
f(f(f(f(f(f(f init hd n )hd n-1 )hd n-2 )hd n-3 )... hd 2 )hd 1 )hd 0