以下代码只是一种原型。我想知道的是为什么它无法编译。
fun test(list) =
let
fun inner(list) =
let
val from = #1(hd(list))
in
if null(tl(list)) = false then innerinner(tl(list),from)
else false
end
fun innerinner(list,from) =
if #2(hd(list)) = from then true
else if null(list) = false then innerinner(tl(list),from)
else false
in
inner(list)
end;
错误消息是:
test.txt:7.34-7.44 Error: unbound variable or constructor: innerinner
test.txt:3.2-9.6 Error: unresolved flex record
(can't tell what fields there are besides #1)
test.txt:10.2-13.13 Error: unresolved flex record
(can't tell what fields there are besides #2)
uncaught exception Error
raised at: ../compiler/Toplevel/interact/evalloop.sml:66.19-66.27
....
我是ML编程的初学者。谁能教我什么是错的?
答案 0 :(得分:2)
你在这里发生了很多事情。如果我们首先看看你得到的错误。
未绑定的变量或构造函数:innerinner
在sml中,你不能在声明之前“使用”它们。它很容易在你的情况下修复
交换函数声明,从而在innerinner
之前声明inner
。
如果您最终遇到想要声明两个相互递归的情况
功能,那么这不是一个选项。在这种情况下,您必须使用关键字and
。
未解决的弹性记录
这有点复杂。这是一个类型错误,与事实有关 元组在内部表示为记录(我建议你去阅读 它)。因此,当您没有提供足够的信息时,类型系统会抱怨。
我认为this QA解释得非常好。总之,你不能拥有无界的元组 因此你需要向类型系统明确它包含多少元素。这个 可以通过显式键入注释函数声明来完成。 但一般情况下,您应该尽可能经常使用模式匹配。
通常,您应始终使用模式匹配而不是元组选择器(#1,#2,...)或列表选择器(hd或tl)。你刚刚看到为什么元组选择器可能“坏”但是使用列表选择器而不测试列表是否为空首先会给你运行时错误(例外)。
在你的代码中加入这样的测试用例会“搞砸”,并使阅读变得混乱。但是如果你使用模式匹配,你的函数定义中会有一些很好的明确切割情况。 通常,你会倾向于编写较少的代码(在我看来)。
顺便说一下,你不需要在函数的单个参数周围添加括号,例如test
函数的主要定义。
总而言之,你的所有功能都可能是这样的:
fun test list =
let
fun innerinner ((x1, x2)::xs,from) =
if x1 = from then true
else innerinner(xs,from)
| innerinner ([], from) = false
fun inner ((x1, x2)::xs) = innerinner(xs,x1)
| inner [] = false
in
inner(list)
end