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では、宣言される前に何かを「使用」することはできません。あなたの場合、関数宣言を入れ替えて、innerinner前に宣言することで簡単に修正できますinner

    たとえば、2つの相互再帰関数を宣言したい場合は、これはオプションではありません。この場合、キーワードを使用する必要があります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 に答える