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
    ,您必须这样说)

  • 你能解释一下这里发生了什么事吗<