如何在 int 列表中转换对列表,其中结果 int 是对的总和
How turn list of pair in list of int, where result int is sum of pair
我尝试使用以下协议定义函数:
[(1,2), (6,5), (9,10)] -> [3, 11, 19]
这是我现在拥有的:
fun sum_pairs (l : (int * int) list) =
if null l
then []
else (#1 hd(l)) + (#2 hd(l))::sum_pairs(tl(l))
根据类型检查器,我有一些 type mismatch
,但我不知道我到底错在哪里。
此代码在 PolyML 5.2 中运行:
fun sum_pairs (l : (int * int) list) =
if null l
then []
else ((#1 (hd l)) + (#2 (hd l))) :: sum_pairs(tl l)
(* ------------^-------------^ *)
与您的区别很小,但很重要:(#1 hd(l))
与 (#1 (hd l))
不同;前者并不像你想的那样 - 它试图提取 hd
的第一个元组字段,这是一个函数!
虽然我们正在做这件事,但我们为什么不尝试重写该函数以使其更加地道呢?对于初学者,我们可以通过函数头中参数的 matching 消除 if
表达式和笨重的元组提取,如下所示:
fun sum_pairs [] = []
| sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
我们将函数分成两个子句,第一个匹配空列表(递归基本情况),第二个匹配非空列表。如您所见,这大大简化了函数,而且在我看来,它更易于阅读。
事实证明,将函数应用于列表元素以生成新列表是一种非常常见的模式。基础库提供了一个名为 map 的内置函数来帮助我们完成这项任务:
fun sum_pairs l = map (fn (a, b) => a + b) l
我在这里使用 anonymous function to add the pairs together. But we can do even better! By exploiting currying 我们可以简单地将函数定义为:
val sum_pairs = map (fn (a, b) => a + b)
函数 map 已柯里化,以便将其应用于函数 returns 接受列表的新函数 - 在本例中为整数对列表。
但是等一下!看起来这个匿名函数只是将加法运算符应用于它的参数!它的确是。让我们也摆脱它:
val sum_pairs = map op+
这里,op+
表示应用加法运算符的内置函数,很像我们的函数文字(上面)所做的。
编辑:后续问题的答案:
- What about arguments types. It looks like you've completely eliminate argument list in the function definition (header). Is it true or I've missed something?
通常编译器能够 infer 来自上下文的类型。例如,给定以下函数:
fun add (a, b) = a + b
编译器可以很容易地推断出类型int * int -> int
,因为参数涉及加法(如果你想要real
,你必须这样说)。
- Could you explain what is happening here
sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
. Sorry for may be dummy question, but I just want to fully understand it. Especially what = means in this context and what order of evaluation of this expression?
这里我们在两个子句中定义了一个函数。第一个子句 sum_pairs [] = []
匹配一个空列表,returns 匹配一个空列表。第二个 sum_pairs ((a, b)::rest) = ...
匹配以一对开头的列表。当您不熟悉函数式编程时,这可能看起来很神奇。但是为了说明发生了什么,我们可以使用 case
重写从句定义,如下所示:
fun sum_pairs l =
case l of
[] => []
| ((a, b)::rest) => (a + b)::sum_pairs(rest)
将按顺序尝试子句,直到匹配一个。如果没有子句匹配,则引发 Match
表达式。例如,如果您省略第一个子句,该函数将始终失败,因为 l
最终将是一个空列表(它从一开始就是空的,或者我们一直递归到最后)。
至于等号,其含义与任何其他函数定义中的含义相同。它将函数的参数与函数体分开。至于评估顺序,最重要的观察是 sum_pairs(rest)
必须发生在 cons (::
) 之前,因此函数不是 tail recursive.
我尝试使用以下协议定义函数:
[(1,2), (6,5), (9,10)] -> [3, 11, 19]
这是我现在拥有的:
fun sum_pairs (l : (int * int) list) =
if null l
then []
else (#1 hd(l)) + (#2 hd(l))::sum_pairs(tl(l))
根据类型检查器,我有一些 type mismatch
,但我不知道我到底错在哪里。
此代码在 PolyML 5.2 中运行:
fun sum_pairs (l : (int * int) list) =
if null l
then []
else ((#1 (hd l)) + (#2 (hd l))) :: sum_pairs(tl l)
(* ------------^-------------^ *)
与您的区别很小,但很重要:(#1 hd(l))
与 (#1 (hd l))
不同;前者并不像你想的那样 - 它试图提取 hd
的第一个元组字段,这是一个函数!
虽然我们正在做这件事,但我们为什么不尝试重写该函数以使其更加地道呢?对于初学者,我们可以通过函数头中参数的 matching 消除 if
表达式和笨重的元组提取,如下所示:
fun sum_pairs [] = []
| sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
我们将函数分成两个子句,第一个匹配空列表(递归基本情况),第二个匹配非空列表。如您所见,这大大简化了函数,而且在我看来,它更易于阅读。
事实证明,将函数应用于列表元素以生成新列表是一种非常常见的模式。基础库提供了一个名为 map 的内置函数来帮助我们完成这项任务:
fun sum_pairs l = map (fn (a, b) => a + b) l
我在这里使用 anonymous function to add the pairs together. But we can do even better! By exploiting currying 我们可以简单地将函数定义为:
val sum_pairs = map (fn (a, b) => a + b)
函数 map 已柯里化,以便将其应用于函数 returns 接受列表的新函数 - 在本例中为整数对列表。
但是等一下!看起来这个匿名函数只是将加法运算符应用于它的参数!它的确是。让我们也摆脱它:
val sum_pairs = map op+
这里,op+
表示应用加法运算符的内置函数,很像我们的函数文字(上面)所做的。
编辑:后续问题的答案:
- What about arguments types. It looks like you've completely eliminate argument list in the function definition (header). Is it true or I've missed something?
通常编译器能够 infer 来自上下文的类型。例如,给定以下函数:
fun add (a, b) = a + b
编译器可以很容易地推断出类型int * int -> int
,因为参数涉及加法(如果你想要real
,你必须这样说)。
- Could you explain what is happening here
sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
. Sorry for may be dummy question, but I just want to fully understand it. Especially what = means in this context and what order of evaluation of this expression?
这里我们在两个子句中定义了一个函数。第一个子句 sum_pairs [] = []
匹配一个空列表,returns 匹配一个空列表。第二个 sum_pairs ((a, b)::rest) = ...
匹配以一对开头的列表。当您不熟悉函数式编程时,这可能看起来很神奇。但是为了说明发生了什么,我们可以使用 case
重写从句定义,如下所示:
fun sum_pairs l =
case l of
[] => []
| ((a, b)::rest) => (a + b)::sum_pairs(rest)
将按顺序尝试子句,直到匹配一个。如果没有子句匹配,则引发 Match
表达式。例如,如果您省略第一个子句,该函数将始终失败,因为 l
最终将是一个空列表(它从一开始就是空的,或者我们一直递归到最后)。
至于等号,其含义与任何其他函数定义中的含义相同。它将函数的参数与函数体分开。至于评估顺序,最重要的观察是 sum_pairs(rest)
必须发生在 cons (::
) 之前,因此函数不是 tail recursive.