这里有一些问题。让我们从您的函数签名开始。
在第一行,您的函数有 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 的用法不正确,因为每一侧的类型都不是布尔值。
我们可以简单地执行两个语句(print(h); printsl(t, k)),而不是使用andalso。像这样的序列是返回最后一个值的表达式。也就是说(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) = true
| printsl(h::t, k) =
if h < k then (print(h); printsl(t))
else printsl(t, k);
fun printsl([], k) = true
| printsl(h::t, 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) = true
| printsl(h::t, 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) = (
if h < k then print(Int.toString h) else ();
printsl(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);