如何递归地在SML / NJ中创建列表列表

时间:2017-03-20 18:16:57

标签: recursion sml smlnj

  

我是SML / NJ的新手,我正在尝试制作一个递归函数   这使得listOfLists。例如:listOf([1,2,3,4])将输出   [[1],[2],[3],[4]]。我在SML / NJ中找到了一个递归merge,我就是   试图用它作为一个大纲:

- fun merge(xs,nil) = xs
= | merge(nil,ys) = ys
= | merge(x::xs, y::ys) =
= if (x < y) then x::merge(xs, y::ys) else y::merge(x::xs,ys);

- fun listOf(xs) = xs
= | listOf(x::xs) = [x]::listOf(xs);
  

我正在尝试使用模式匹配,我对它有点困惑。我   非常确定x是头部,然后xs是尾部,但我可以   错误。所以我要做的就是使用列表的头部,使它成为一个   列表,然后将其添加到列表的其余部分。但是在尝试的时候   这个函数,我收到错误:

stdIn:15.19-15.34 Error: operator and operand don't agree [circularity]
  operator domain: 'Z list * 'Z list list
  operand:         'Z list * 'Z list
  in expression:
    (x :: nil) :: listOf xs
  

这个错误对我来说很陌生,因为我没有任何经验   与sml / nj。如何修复listOf函数?

1 个答案:

答案 0 :(得分:0)

你很亲密。问题是在模式匹配中,像xs(只是变量)这样的模式可以匹配任何。以s结束它的事实并不意味着该模式只能匹配列表的尾部。以这种方式使用s只是SML中的程序员约定。

因此,在你的定义中:

fun listOf(xs) = xs
|   listOf(x::xs) = [x]::listOf(xs);

第一行告诉SML将所有值保持不变,这显然不是你的意图。 SML检测到这与您 尝试更改值的第二行不一致。

您需要更改第一行,以便它不匹配所有内容。将merge函数视为模板,需要与基础案例匹配的内容。自然基础情况为nil(也可以写为[])。请注意nilmerge定义中扮演的角色。如果对函数定义第一行中的模式使用nil而不是xs,则第二行完全符合您的要求,并且函数将按预期工作:

fun listOf(nil) = nil
|   listOf(x::xs) = [x]::listOf(xs);