1

標準 ML に次のコードがあります。

datatype a = a;
val x = a;
val y:a = a;
val z = a;

fun fa a = a;

fun not' x = case x of
    true => false
  | false => true;

fun fst (a,b) = a;
fun snd (a,b) = b;

合計タイプ ( not') に対する関数は問題なく動作しますが、積タイプ ( ) に対して関数を使用しようとすると、次のfstエラーが発生します。

- fst (1,2);
! Toplevel input:
! fst (1,2);
!      ^
! Type clash: expression of type
!   int
! cannot have type
!   a
-  

なんで?

4

1 に答える 1

1

変数名とスコープについてもっと意識する必要があります。

何が起こっているかというと、型コンストラクターaと値コンストラクターを使用してデータ型を宣言したということですa。次に、後でand関数aの引数として使用します。これは、データ型のその値コンストラクターに一致していることを意味します。おそらくあなたが意図したものではありません。fstsnda

簡単な修正は、2 つの関数で使用される変数名を変更することです。

fun fst (x, y) = x;
fun snd (x, y) = y;

- fst(1,2);
val it = 1 : int

通常、問題はタイプから簡単に確認できますが、使用するのにかなり不幸な名前を選択したため、関数の元のタイプは

val fst = fn : a * 'a -> a
val snd = fn : a * 'a -> 'a

しかし、関数がデータ型 a を参照しないように修正されると、'a代わりにa を持つことになります。

val fst = fn : 'a * 'b -> 'a
val snd = fn : 'a * 'b -> 'b

一般に、値コンストラクターの場合は大文字で開始し、型コンストラクターの場合はすべて小文字で開始するのが良いスタイルと考えられています。1 つの例はオプションのデータ型ですが、値のコンストラクターにはすべて大文字を使用します (これを強制する他の言語もあります)。

datatype 'a option = NONE 
                   | SOME of 'a

型と値に使用される名前を分離し、それを「最初の」ポリモーフィック型変数の一部としても使用されるため、「a」以外の名前で呼ぶと、全体の考え方がより理にかなっている可能性があります (つまり、ほとんどのインタープリターは'a)。

datatype foo = Bar;
val x = Bar;
val y:foo = Bar;
val z = Bar;

fun fa Bar = Bar;
于 2013-04-02T13:48:34.113 に答える