2016-10-12 6 views
2

私はリストの長さを取得する関数を書く必要がある代入に取り組んでいます。これは簡単な作業ですが、わからないことがあります。SML演算子とオペランドがfoldrで一致しない

私の単純なコード

val len = foldr (fn(_, y) => y + 1) 0 

警告この警告生成:型がダミーの型にインスタンス化されるための 値の制限を一般化しませVARS(X1、X2を、...)

これをREPLで実行しようとすると、次のようになります。

len [1, 2, 3, 4]; 
stdIn:18.1-18.17 Error: operator and operand don't agree [overload conflict] 
operator domain: ?.X1 list operand:  
[int ty] list in expression: 
    len (1 :: 2 :: 3 :: <exp> :: <exp>) 

なぜこれが機能しないのかわかりません。私はいくつかの関数型プログラミングの原則を知っています。もちろん

私はこの

fun len xs = foldr (fn(_, y) => y + 1) 0 xs 

のように、一部のアプリケーションなしでそれを動作させることができますが、私は最初のバージョンが動作しない理由を理解したいと思います。

答えて

3

これはvalue restrictionルールアプリケーションのインスタンスである:

要するに

、値制限は、式の右辺の構文値であれば一般にのみ発生する可能性があることを述べています。

構文的には、

foldr (fn(_, y) => y + 1) 0 

ではない、それは多型タイプが割り当てられていない理由です、関数適用です。ダミータイプでインスタンス化されました。これは動作します:

len [] 

が、ほとんどのケースでlenvalのように定義は無用です。

この制限は、変数割当(参照による)の存在下で型の安全を保証するために存在します。詳細は、リンク先のページを参照してください。

+0

私は見ているので、型は割り当てられていません...しかし、なぜ型が 'foldr'関数から推測されないのでしょうか?部分的なアプリケーションは、最初の2つの引数がなくても、 'foldr'と同じ型の関数* value *であると思うでしょう。 – Pavlin

+0

実際、2つのアプリケーションを持つ用語は関数の値にまで減少しますが、コンパイラはこれを構文的に扱います*。これは*何も減らさないことを意味し、単に用語の形を見ます。時にはこのルールは過度に慎重であり、適切に動作するプログラムを拒否します。何らかのタイプのシステムが '1 +(0なら0、次に1が真)のようなものを拒否します。しかし、タイプセーフティーを支払うのはちょっとした代償です。また、ランタイムオーバーヘッドが発生することもなく、これも重要です。 –

関連する問題