0

下面的代码只是一种原型。我想知道的是为什么它无法编译。

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 编程的初学者。谁能教我什么是错的?

4

1 回答 1

2

你在这里发生了很多事情。如果我们首先查看您遇到的错误。

  1. 未绑定的变量或构造函数:innerinner

    在 sml 中,您不能在声明之前“使用”东西。在您的情况下,通过交换函数声明并因此innerinnerinner.

    如果您最终遇到想要声明两个相互递归函数的情况,那么这不是一个选项。在这种情况下,您必须使用关键字and

  2. 未解决的弹性记录

    这有点复杂。这是一个类型错误,与元组在内部表示为记录的事实有关(我建议你去阅读它)。因此,当您没有提供足够的信息时,类型系统会抱怨。

    我认为这个 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
于 2012-09-27T01:21:38.197 回答