帮我解释一下这个 F# 递归示例程序
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。 有人可以帮助我吗?
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];;
Got this example from "Functional Programming for the Real world" by Thomas Petricek
I don't understand in second branch in that pattern matching: f rem hd.
Could somebody help me?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
让我们首先分解一下
aggregateList
函数声明。该函数采用三个参数:int
并返回第三个int
。然后,该函数将与提供给它的列表进行以下两种可能性之一的匹配:
init
的值。hd
(或 head),并将列表的其余部分分配给tl
(或尾巴)。然后它执行递归调用aggregateList f init tl
。当返回时,它获取结果并将其分配给rem
。然后它在rem
和hd
上调用f
。正如其他人指出的那样,这与
的作用相同基本 F# 库中的 List.foldback
函数。当然,要小心地正确选择
init
值,因为如果执行aggregateList mul 0 somelist;;
你只会得到0
no无论您提供什么清单。Let's break down the
aggregateList
function declaration first. The function takes three parameters:int
s and returns a thirdint
.The function then matches the list it is supplied with one of two possibilities:
init
.hd
(or head) and the rest of the list and assigns it totl
(or tail). Then it performs the recursive callaggregateList f init tl
. When that returns, it takes the result and assigns it torem
. Then it callsf
onrem
andhd
.As other people have pointed out, this does the same thing as the
List.foldback
function in the basic F# library.Be careful, of course, to choose the
init
value properly because if you executedaggregateList mul 0 somelist;;
you'll just get0
no matter what list you supply.它调用函数 f(参数之一),给出递归调用的结果和下一项。
rem
是余数,或者在本例中是余数值的结果。hd
是下一项,如| 中所示。 hd::tl ->
模式匹配的一部分。实际上,这个聚合函数采用一个函数、一个起点和一个列表。表示示例行的一种方法是:
It calls the function f (one of the parameters) giving it the result of the recursive call and the next item.
rem
is the remainder, or in this case the result of the remainder of the values.hd
is the next item, as seen in the| hd::tl ->
part of the pattern matching.Effectively this aggregate function takes a function, a starting point, and a list. A way of representing the example line is:
只是为了好玩,让我们做一些
printf
风格的调试:看起来该函数相当于
List.foldBack
(或其他语言中的fold_right
) :它从右到左遍历列表中的每个项目并调用它们的函数f
。让我们用几种不同的方式重写该函数:
您可以像这样使用该函数:
那么,让我们从我们已经了解的 F# 函数开始:
f
是一个类型为int ->; 的函数。整数-> int
。您传递函数就像传递任何其他变量(例如整数或字符串)一样。f rem hd
使用两个参数调用函数f
:rem
和hd
。那么回到原来的函数:
在第 1 行中,我们使用
tl
反复调用aggregateList
。由于列表变得越来越小,我们最终会遇到 nil 情况,它返回init
。在第 2 行中,
f rem hd
是函数的返回值。然而,由于我们在到达列表末尾时递归了堆栈,因此当我们沿着堆栈跟踪向上走时,我们将针对每个元素(按从右到左的顺序)调用此函数。给定
aggregateList (+) 0 [1..10]
,nil 情况返回0
,因此我们调用:列表中没有更多项目,因此整个函数返回
55
。正如您可以想象的,对于长度为 n 的列表,
aggregateList
中的嵌套调用的计算方式如下:f (f (f (f (f (f (f (f init) hdn) hdn-1) hdn-2) hdn-3) ... hd 2) 高清1) 高清0
Just for fun, let's do some
printf
style debugging:It looks like the function is equivalent to
List.foldBack
(orfold_right
in other languages): it walks each item in the list from right to left and invokes a functionf
on them.Let's re-write the function in a few different ways:
You'd use the function like this:
So let's start with what we already know about F# functions:
f
is a function with the typeint -> int -> int
. You pass functions around as if they were any other variable like ints or strings.f rem hd
invokes the functionf
with two arguments,rem
andhd
.So going back to the original function:
In line 1, we call
aggregateList
recusively withtl
. Since the list gets smaller and smaller, we're eventually going to hit the nil case, which returnsinit
.In line 2,
f rem hd
is the function's return value. However, since we recursed down the stack as we made our way to end of the list, we're going to call this function one for each element (in right-to-left order) as we walk back up the stack trace.Given
aggregateList (+) 0 [1..10]
, the nil case returns0
, so we call:No more items in the list, so the whole function returns
55
.As you can imagine, the nested calls in
aggregateList
evaluate like this for a list of lengthn
:f (f (f (f (f (f (f (f init hdn) hdn-1) hdn-2) hdn-3) ... hd2) hd1) hd0