如何在 SML 中的 if 语句中打印

问题描述

这是我试过的代码

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.appList.filter 以更实用的方式编写整个程序。

fun printsl (xs,k) =
  List.app
    (fn y => print (Int.toString y))
    (List.filter
      (fn x => x < k)
      xs);