2012-09-27 76 views
0

下面的代碼只是一種原型。我想知道的是爲什麼它不能編譯。ML代碼錯誤的原因

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編程的一種初學者。任何人都可以教我什麼是錯的?

回答

2

你在這裏有很多事情要做。如果我們先看看你遇到的錯誤。

  1. 綁定變量或構造函數:innerinner

    在SML你不能「用」已經申報前的東西了。通過 交換函數聲明並在inner之前聲明innerinner很容易在你的情況下被修復。

    如果你想要例如聲明兩個相互遞歸的 函數,那麼這不是一個選項。在這種情況下,您將不得不使用關鍵字and

  2. 懸而未決的柔性記錄

    這是一個比較複雜一點。這是一個類型錯誤,並且與事實 有關,即元組在內部被表示爲記錄(我建議你去閱讀關於它的 它)。因此,當你不提供足夠的信息時,類型系統會投訴。

    我認爲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 
+1

或許'X1 =從否則別指望innerinner(XS,來自)';)引起的 –

+0

,但儘量不惹到很多與原來的功能和冒着失去我的觀點:) –

相關問題