Sml 如何在ML中创建平面列表函数?

Sml 如何在ML中创建平面列表函数?,sml,ml,Sml,Ml,我得到一个练习,要求我编写一个函数flatlist,该函数获取列表列表,并通过返回原始列表中所有列表的串联来“展平”列表 例如: flatlist([1,2], [6,7], [9]) = [1,2,6,7,9] 下面的代码就是我尝试的代码 fun flatlist([]) = [] | flatlist(a::rest) = (a::rest); 我在编写函数时没有收到错误消息,但在REPL中尝试函数并在示例中应用该函数时遇到问题。要求您编写的函数通常称为concat,并且恰好位于标准

我得到一个练习,要求我编写一个函数
flatlist
,该函数获取列表列表,并通过返回原始列表中所有列表的串联来“展平”列表

例如:

flatlist([1,2], [6,7], [9]) = [1,2,6,7,9]
下面的代码就是我尝试的代码

fun flatlist([]) = []
  | flatlist(a::rest) = (a::rest);

我在编写函数时没有收到错误消息,但在REPL中尝试函数并在示例中应用该函数时遇到问题。

要求您编写的函数通常称为
concat
,并且恰好位于标准库中的
List.concat
名称下。尽管如此,编写这样一个递归函数仍然是一个很好的练习。你的函数确实会进行类型检查和编译,除了有一个你还没有发现的细微缺陷

关于语法 首先,关于空格和括号,我可能会对您的第一次尝试的格式稍有不同:

(* Before *)
fun flatlist([]) = []
  | flatlist(a::rest) = (a::rest);

(* After *)
fun flatlist [] = []
  | flatlist (xs :: xss) = xs :: xss
这里的要点是:

  • 因为第一个元素本身就是一个列表,所以我喜欢给它取一个复数名,
    xs
    ,因为其余的是一个事物列表,所以我喜欢给它取一个双复数名。但是
    xs::rest也可以。这样我们就不会把读者和
    x
    混淆,这是一个单数任意值的好名字

  • []
    模式周围的括号是不必要的,因为
    []
    是单个组合符,因此不需要消除歧义。但是,模式xs::xss
    确实需要一个括号,因为它包含一个中缀模式构造函数,该构造函数接受多个参数。如果我们忽略它,就像这样:

    fun flatlist [] = []
      | flatlist xs :: xss = xs :: xss
    
    我们将收到以下警告(在莫斯科):

  • 另一方面,
    xs::xss
    函数体周围的括号不需要括号,因为函数体在语法上是为单个表达式保留的,
    xs::xss
    。这里没有必要消除歧义

  • 结尾
    也不是严格必需的,除非您将此函数复制粘贴到REPL中,而不是将其放入文件中。所以,只要你的函数很短,你就只需将它们复制粘贴到REPL中来尝试它们,拥有
    很好。当您开始构建更大的函数并一次执行整个文件时,您最好将其忽略

这里的主要收获,也与将此函数应用于值时遇到的问题有关,可能来自于您对编程语言的经验,对于这些语言,函数应用程序看起来像括号中的
f(x)
“前面是函数名,中间是它的参数

SML函数不同:函数应用程序的最简单形式类似于
fx
。需要使用括号来消除歧义,例如,
f(x+2)
(f x)+2
,但不需要括号来表示这是函数应用程序。函数名和值之间的空格会处理这个问题

分析初始解 您遇到的第一个问题是将列表列表传递给函数。在您的示例中,您实际要做的是传递一个三元组,
(x,y,z)
,其中
x
y
z
是列表。此值的类型为
int list*int list*int list
,而不是函数
flatlist
所期望的
int list
。这是因为SML中的括号(当括号中有逗号时)用于表示元组,而不是“函数的参数”

尝试一个整数列表,它会给出:

- flatlist [[1,2], [6,7], [9]];
> val it = [[1, 2], [6, 7], [9]] : int list list
塔达!等等

让我们通过一次减少表达式的一部分来评估您第一次尝试的
flatlist
。在这里,我使用
意思是“减少到”:

因此,您当前的
flatlist
是一个非常复杂的列表

正确解决方案的提示 因此,您拥有基本的递归权限,但在每个递归状态下需要执行的操作有点不正确。它不仅仅是作为函数体的
xs::xss
,因为这将产生与输入完全相同的输出。对于
xss
中的所有列表,您必须以某种方式将列表
xs
的元素与下一个列表的元素递归地连接起来

提示:
@
运算符(发音为“append”)

- flatlist [[1,2], [6,7], [9]];
> val it = [[1, 2], [6, 7], [9]] : int list list
  flatlist [[1,2], [6,7], [9]]          (* x = [1,2], xs = [[6,7], [9]] *)
⇒ [1,2] :: flatlist [[6,7], [9]]        (* x = [6,7], xs = [[9]] *)
⇒ [1,2] :: [6,7] :: flatlist [[9]]      (* x = [9], xs = [] *)
⇒ [1,2] :: [6,7] :: [9] :: flatlist []  (* base case *)
⇒ [1,2] :: [6,7] :: [9] :: []           (* just another way to write *)
⇒ [[1,2], [6,7], [9]]