0

n与えられた数値が完全平方かどうかを調べる関数を書き込もうとしています。これが私の試みです:

local
  fun perfect_square_iter x z = let val sqr = z * z in
    case (x,z) of
        (sqr,_) => true
      | (_, 0) => false
      | _ => perfect_square_iter x (z - 1)
    end
in fun perfect_square n = perfect_square_iter n n
end

これを で実行しようとするとsml myfile.sml、次のエラーが表示されます。

lab03.sml:17.5-20.43 Error: match redundant
          (sqr,_) => ...
    -->   (_,0) => ...
    -->   _ => ...

/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0
 raised at ../compiler/FLINT/trans/translate.sml:1735.13-1735.21

これは、2 つの定数にのみ一致し、それ以外のすべてに一致するため、冗長なパターンではないようです。コンパイラがこれを冗長と見なすのはなぜですか?

4

1 に答える 1

1

sqrlet バインディングが与えられたとしても、定数ではありません。構文的には変数であり、パターンの言語では、すべての変数は何にでも一致する自由な変数です。したがって、パターン(sqr,_)はすべての引数に一致します。コンマの前の値はsqr、その句の本体 (の RHS =>) にバインドされるため、z*z へのバインドが隠され、その後の値は破棄されます。これは考えられるすべてのケースをカバーするため、残りの一致は冗長です。

次の (絶対にひどい) コードを検討することで、パターン内の変数の一致によって新しいローカル スコープが導入されることを確認できます。

fun f xs =
    let val x = 5 in
        case xs of
            [] => 0
        |   x::xs => x
    end;

コンパイルされますが、たとえばf [1,7,10]、5 ではなく 1 が返されます。

if ... then ... elseコードでは、パターン マッチングではなく、 のケースを処理するために使用する必要がありますx = sqr。何かのようなもの

(_,0) => false
| (_,_) => if x = sqr ...

(これは、パターン マッチングを引き続き使用することを前提としていますが、必要な方法でパターン マッチングを使用することはできないため、コードをより根本的に再構築して、たとえば を不要にするletことが適切である可能性があります)。

于 2015-10-09T20:20:16.010 に答える