何がこの標準-MLタイプエラーの原因は?
-
13-09-2019 - |
質問
私はこの非常に単純なSML関数の末尾再帰バージョンを作成しようとしていた。
fun suffixes [] = [[]]
| suffixes (x::xs) = (x::xs) :: suffixes xs;
このの過程で、私はPARAMATERSに型注釈を使用していました。次のコードはこれを示し、Iは、単にタイプの注釈を削除する一方、(下記の)タイプエラーが発生し、SMLは、上記の単純な関数として全機能を同じシグネチャを与え、問題なくそれを受け入れます。
fun suffixes_tail xs =
let
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs:'a list) (acc:'b list) =
suffixes_helper xs ((x::xs)::acc)
in
suffixes_helper xs []
end;
エラー:
$ sml typeerror.sml
Standard ML of New Jersey v110.71 [built: Thu Sep 17 16:48:42 2009]
[opening typeerror.sml]
val suffixes = fn : 'a list -> 'a list list
typeerror.sml:17.81-17.93 Error: operator and operand don't agree [UBOUND match]
operator domain: 'a list * 'a list list
operand: 'a list * 'b list
in expression:
(x :: xs) :: acc
typeerror.sml:16.13-17.94 Error: types of rules don't agree [UBOUND match]
earlier rule(s): 'a list * 'Z list list -> 'Z list list
this rule: 'a list * 'b list -> 'Y
in rule:
(x :: xs : 'a list,acc : 'b list) =>
(suffixes_helper xs) ((x :: xs) :: acc)
/usr/local/smlnj-110.71/bin/sml: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
与えられた2個のエラーがあります。後者は、ここでsuffixes_helperの2つの節の間のミスマッチそれほど重要であると考えられます。最初は、私は理解していないものです。私は、最初のパラメータの型が'a:list
と第2 paramは型'b:list
であることであることを述べるために注釈を付けます。私はそれを理解して、一般的な統一の上部に構築されたヒンドリー - ミルナー型推論アルゴリズムは、'b:list
の置換を使用して、'a:list list
と'b ---> 'a list
を統一することはできないか。
編集:答えは、それはある意味で型注釈によって与えられたものより厳しい推論された型を許可しない型推論アルゴリズムとは何かを持っていることを示唆しています。私は、このようなルールはパラメータのみで、全体としての機能上の注釈にも適用されることを推測します。これが正しければ、私は考えています。いずれにせよ、私は関数本体に上型注釈を移動しようとした、と私は、エラーの同じ種類を取得します:
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs) acc =
suffixes_helper (xs:'a list) (((x::xs)::acc):'b list);
エラーは以下のようになります。
typeerror.sml:5.67-5.89 Error: expression doesn't match constraint [UBOUND match]
expression: 'a list list
constraint: 'b list
in expression:
(x :: xs) :: acc: 'b list
解決
私はSMLわからないけど、F#、他の関数型言語、このような状況で警告を与えます。エラーを与えることは少し厳しいことが、それは理にかなっていることがあります。プログラマは、余分なタイプの変数紹介する場合は、「Bを、そして場合は、」bがリスト」タイプのものでなければならないプログラマが意図したように、関数は、一般的なようではない可能性があります価値の報告がある。
他のヒント
この作品ます:
fun suffixes_tail xs =
let
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs:'a list) (acc:'a list list) =
suffixes_helper xs ((x::xs)::acc)
in
suffixes_helper xs []
end
ヨハとnewacctとしては'b list
が緩すぎる、と言います。明示的な型注釈を与えた場合、
fun suffixes_helper (_ : 'a list) (_ : 'b list) = ...
これは、暗黙のうちに
として定量化されますfun suffixes_helper (_ : (All 'a).'a list) (_ : (All 'b).'b list) = ...
と明らかに'b = 'a list
は同時に(All a')
のとの(All b')
trueにすることはできません。
明示的な型注釈がなければ、型推論は、種類を統一することで正しいことを、行うことができます。そして実際に、SMLの型システムは、そのように明示的な型注釈が必要になることはありません、決定不能になることはありません(私の知る限り承知のように)ということは十分に簡単です。なぜ、あなたはここに入れたいのですか?
あなたは'a
と'b
がの、の独立は、ののものに設定することができることを意味し'a
と'b
、のようなタイプの変数を使用する場合。私は'b
がint
と'a
がfloat
であったことを決めたのであれば、たとえばそれが動作するはずです。それは'b
が'a list
しなければならないことが判明したので、しかし、明らかに、それはこの場合には有効ではありません。