Sml 如何在int列表中旋转对列表,其中结果int是对的和
我尝试使用以下协议定义函数:Sml 如何在int列表中旋转对列表,其中结果int是对的和,sml,ml,Sml,Ml,我尝试使用以下协议定义函数: [(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)) 根据类型检查器,我有一些类型不匹配,但我无法找出我的确切错误所在。此代码在PolyML 5.2中运行: fun sum_pairs (l : (int
[(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))
根据类型检查器,我有一些
类型不匹配
,但我无法找出我的确切错误所在。此代码在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)
(* ------------^-------------^ *)
与您的区别很微妙,但很重要:(#1hd(l))
不同于(#1hd(l))
;前者不做您认为的事情-它试图提取hd
的第一个元组字段,这是一个函数
当我们在做这个时,为什么不尝试重写这个函数,使它更地道一点呢?首先,我们可以通过对函数头中的参数执行以下操作来消除if
表达式和笨拙的元组提取:
fun sum_pairs [] = []
| sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
我们已经将函数拆分为两个子句,第一个子句匹配空列表(递归基本情况),第二个子句匹配非空列表。如您所见,这大大简化了函数,并且在我看来,使其更易于阅读
事实证明,将函数应用于列表元素以生成新列表是一种非常常见的模式。basis库提供了一个调用的内置函数,以帮助我们完成此任务:
fun sum_pairs l = map (fn (a, b) => a + b) l
在这里,我使用一个函数将这些对添加到一起。但我们可以做得更好!通过利用,我们可以简单地将函数定义为:
val sum_pairs = map (fn (a, b) => a + b)
该函数是curry函数,因此将其应用于函数将返回一个新函数,该函数接受一个列表——在本例中是一个整数对列表
但是等一下!看起来这个匿名函数只是将加法运算符应用于它的参数!的确如此。让我们也摆脱它:
val sum_pairs = map op+
这里,op+
表示一个应用加法运算符的内置函数,很像我们的函数literal(上文)所做的那样
编辑:后续问题的答案:
fun add (a, b) = a + b
编译器可以很容易地推断出类型int*int->int
,因为参数包含在加法中(如果您想要real
,您必须这样说)
sum\u pairs((a,b)::rest)=(a+b)::sum\u pairs(rest)
。对不起,这可能是一个愚蠢的问题,但我只想完全理解它。特别是在这个上下文中,=意味着什么,这个表达式的求值顺序是什么sum\u pairs[]=[]
,匹配一个空列表并返回一个空列表。第二个,sum_pairs((a,b)::rest)=……,匹配以对开头的列表。当您刚接触函数式编程时,这可能看起来很神奇。但是为了说明发生了什么,我们可以使用case
重写子句定义,如下所示:
fun sum_pairs l =
case l of
[] => []
| ((a, b)::rest) => (a + b)::sum_pairs(rest)
这些条款将按顺序进行试验,直到其中一个条款匹配为止。如果没有匹配的子句,则引发Match
表达式。例如,如果省略了第一个子句,函数将始终失败,因为l
最终将是空列表(要么从一开始就是空的,要么我们一直递归到最后)
至于等号,它的含义与任何其他函数定义中的相同。它将函数的参数与函数体分离。至于求值顺序,最重要的观察是
求和对(rest)
必须发生在cons(:
)之前,因此函数不是这样。此代码在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)
(* ------------^-------------^ *)
与您的区别很微妙,但很重要:(#1hd(l))
不同于(#1hd(l))
;前者不做您认为的事情-它试图提取hd
的第一个元组字段,这是一个函数
当我们在做这个时,为什么不尝试重写这个函数,使它更地道一点呢?首先,我们可以通过对函数头中的参数执行以下操作来消除if
表达式和笨拙的元组提取:
fun sum_pairs [] = []
| sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
我们已经将函数拆分为两个子句,第一个子句匹配空列表(递归基本情况),第二个子句匹配非空列表。如您所见,这大大简化了函数,并且在我看来,使其更易于阅读
事实证明,将函数应用于列表元素以生成新列表是一种非常常见的模式。basis库提供了一个调用的内置函数,以帮助我们完成此任务:
fun sum_pairs l = map (fn (a, b) => a + b) l
在这里,我使用一个函数将这些对添加到一起。但我们可以做得更好!通过利用,我们可以简单地将函数定义为:
val sum_pairs = map (fn (a, b) => a + b)
该函数是curry函数,因此将其应用于函数将返回一个新函数,该函数接受一个列表——在本例中是一个整数对列表
但是等一下!看起来这个匿名函数只是将加法运算符应用于它的参数!的确如此。让我们也摆脱它:
val sum_pairs = map op+
这里,op+
表示一个应用加法运算符的内置函数,很像我们的函数literal(上文)所做的那样
编辑:后续问题的答案:
fun add (a, b) = a + b
编译器可以很容易地推断出类型int*int->int
,因为参数包含在加法中(如果您想要real
,您必须这样说)