-
您应该使用模式匹配而不是使用null x
, hd x
and tl x
。
这也适用于分解元组和记录。例如
fun number_in_month ((x1, x2, x3) :: xs, m) = ...
或者,因为我们从未使用过 x1 和 x3
fun number_in_month ((_, x2, _) :: xs, m) = ...
这样可以清楚地看到第一个参数是一个三元组列表,并且没有类型注释
需要
此外,当您省略显式类型注释时,这就是拥有类型系统的整个想法
可以为您推断它们(请参阅下一点),然后这段代码
fun foo42 xs = map (fn x => #2 x) xs
会给你一些关于“未解决的弹性记录”的令人讨厌的错误(此错误消息来自 SML/NJ)
/tmp/sml20620PlF:105.5-105.44 Error: unresolved flex record
(can't tell what fields there are besides #2)
通过分解三元组可以很容易地修复
fun foo42 xs = map (fn (_, x2, _) => x2) xs
-
说到类型注释。它们(几乎总是)不需要,而且它们会弄乱
代码的可读性。更不用说它们不必要地限制了您使用的类型
可以用在.
此外,根据您真正想要的,您给出的类型注释是错误的。你
应该有括号int * int * int
。目前它被解释为
两个 int 和一个 int 列表的 3 元组int * int * (int list)
.
如果你真的坚持用类型注释你的函数,那么你可以这样做
val number_in_month : (int * int * int) list * int -> int =
fn ([] , m) => 0
| ((_,x2,_) :: xs, m) => 42
这“几乎”像 Haskell,类型在函数声明之前给出。
-
尝试使代码缩进方式更加一致。这会让你更加清晰。
在这里,我特别考虑了您缩进的方式else
部分结束in ... end
部分。下面的部分显然在很多方面仍然是错误的,我无法开始想象,但它
给出了如何做的想法
fun number_in_month(x : int*int*int list, m: int) =
if null x then 0
else
let fun inc x = x + 1;
in
val counter = 0;
if m = #2 (hd x) andalso m > 0 then
inc counter
number_in_month((tl x), m)
else
number_in_month((tl x), m)
end
-
你不能声明一个变量val counter = 0
在 - 的里面in ... end
let 表达式的一部分。
let 表达式的语义是
let
dec
in
exp_1; ...; exp_n
end
因此所有声明(函数和值绑定等)都必须放在let ... in
part.
根本没有必要有增量函数,它只会扰乱可读性。
请记住,SML 使用单一赋值,因此变量在声明后是不可变的。
-
嵌套 if 表达式中的序列事物
inc counter
number_in_month((tl x), m)
完全没有意义。可以在表达式中包含多个表达式的唯一方法then ... else
部分(实际上是任何需要单个表达式的地方),带有
序列 (exp_1; ...; exp_n)。然而,这仅当除最后一个表达式之外的所有表达式都可用时才可用
副作用,因为它们的结果被忽略/丢弃
- (print "Foo\n"; print "Bar\n"; 42);
Foo
Bar
val it = 42 : int