问题描述
这是我试过的代码
fun printsl([],k) = true
| printsl(h::t) = if k > h then print(h) andalso printsl(t);
= stdIn:4.68-7.8 Error: Syntax error: deleting SEMICOLON ID
stdIn:8.1 Error: Syntax error found at EOF
该函数的目标是打印列表中小于值k
的任意数字
解决方法
这里有一些错误。让我们从您的函数签名开始。
在第一行,您的函数接受 2 个参数、一个空列表以及 k
的类型(这还不重要)。然后在第二行,该函数只接受一个参数,一个非空列表。
这两行应该匹配如下:
fun printsl([],k) = ...
| printsl(h::t,k) = ...
现在让我们考虑一下 andalso
的使用。 andalso
是一个运算符,它接受两个布尔值并返回一个布尔值。可以认为它具有签名bool * bool -> bool
。
您的用法 print(h) andalso printsl(t)
与此签名不匹配。
print
的类型是 string -> unit
,所以 print(h)
的类型是 unit
(假设 h
是一个字符串)。因此,andalso
的用法是不正确的,因为每一侧的类型都不是 bool。
我们可以简单地执行两个语句 andalso
,而不是使用 (print(h); printsl(t,k))
。像这样的序列是返回最后一个值的表达式。也就是说(x; y; z)
返回z
。
fun printsl([],k) = true
| printsl(h::t,k) = if h < k then (print(h); printsl(t,k));
然而,这仍然被破坏,因为 SML 中的 if-else 构造是一个表达式,并且必须有一个匹配的 else,因此您可以使用以下任一方法:
fun printsl([],k) =
if h < k then (print(h); printsl(t))
else printsl(t,k);
fun printsl([],k) = (
if h < k then print(h) else ();
printsl(t,k)
);
我个人更喜欢后者,因为它可以防止重复 printsl
。
这段代码会编译,但是签名是错误的。由于我们直接使用 h
作为 print
的参数,因此推断其类型为 string
。这意味着编译器确定 printsl
具有类型 string list * string -> bool
,而我们的目标是 int list * int -> bool
。
这可以通过将调用 print(h)
更改为 print(Int.toString h)
来纠正,给我们:
fun printsl([],k) = (
if h < k then print(Int.toString h) else ();
printsl(t,k)
);
这是一个函数,它将打印给定列表中小于 k
的所有值,但它始终返回 true。这没有提供额外的信息,所以我倾向于将签名更改为 int list * int -> unit
,给我们(最后):
fun printsl([],k) = ()
| printsl(h::t,k)
);
还可以使用 List.app
和 List.filter
以更实用的方式编写整个程序。
fun printsl (xs,k) =
List.app
(fn y => print (Int.toString y))
(List.filter
(fn x => x < k)
xs);