2013-07-29 7 views
7

弱い多型に関して少し混乱しています。OCamlです。コンパイラは、ポリモーフィック型の'a -> 'aを推測することができ、かつcacheが局部的に使用されているOCamlの弱い多型

let remember x = 
    let cache = ref None in 
     match !cache with 
     | Some y -> y 
     | None -> cache := Some x; x 
;; 

私は機能rememberを定義し、次のスニペットを参照してください。

しかし、私は

let remember = 
    let cache = ref None in 
    (fun x -> match !cache with 
     | Some y -> y 
     | None -> cache := Some x; x) 
;; 
に上記のコードを変更し、コンパイラが弱いポリモーフィック型の '_a -> '_aを推測する場合、また、 cacherememberの呼び出し間で共有されているようです。

ここでコンパイラは弱い多型を推測していますが、なぜcacheが共有されるのですか?私は再び

let remember x = 
    let cache = ref None in 
    (fun z -> match !cache with 
     | Some y -> z 
     | None -> cache := Some x; x) 
;; 

を、コードを変更した場合

は、詳細は何ですか、コンパイラは'a -> 'a -> 'acacheがローカルで使用状態になる多相型を推論します。これはなぜですか?

答えて

8
let remember = 
let cache = ref None in 
    (fun x -> match !cache with 
     | Some y -> y 
     | None -> cache := Some x; x) 
;; 

ここでcacheは、返された関数によって閉じられます。しかし、cacheと宣言している時点では、そのタイプについては何の情報もありません。 rememberが定義されている場合は、xのタイプが何であってもcacheが作成されます。

しかし、これは、我々はこのような何か行うことができます閉鎖されているので:私たちは実際にそれで何かを保存したので、

> remember 1 
    1 

今ではcache : int option refことは明らかですが。 cacheは1つだけなので、rememberは1つのタイプしか保存できません。

次の1つでは、xcacheの2つのものを閉じます。 rememberの呼び出しごとに新しいcache refを作成するので、この型は完全に多型になります。型が弱い多形ではない理由は、を格納することを知っており、cacheが作成された時点でxの型を持つためです。上記の2つのバージョンが

+0

'cache'は' ref(None int) 'ではなく' int option ref'型を持っていると思います。 – Virgile

+0

@Virgileあまりにも多くのhaskell – jozefg

6

これは価値の制限と同じようです。完全な値の制限(SMLのような)はあなたのコードを完全に拒否します。場合cacheが呼び出し間で共有されているという事実が明らかである

http://caml.inria.fr/pub/papers/garrigue-value_restriction-fiwflp04.pdf

:弱ポリモーフィック型は、紙、私は確かにちょうどあなたの質問を読んだ後につまずいたジャック・Garrigueのことで、「値の制限をリラックス」で説明されていますあなたはMLコードが意味するものの正しい精神モデルを持っています。 remembercacheの2つの値を定義しています。ネスティングでは、単にcacheの範囲をブロックに限定します。

0
let remember x = 
    let cache = ref None in 
     match !cache with 
     | Some y -> y 
     | None -> cache := Some x; x 


let remember x = 
    let cache = ref None in 
    (fun z -> match !cache with 
     | Some y -> z 
     | None -> cache := Some x; x) 

rememberは「ダイレクト」機能で、あなたはremember 1のようにそれを呼び出すたびに、それはref Noneからcacheを初期化します、そうではありませんか?実際には、何も覚えていないので、cacherememberコールの間で共有されません。他のバージョンにおいて


let remember = 
    let cache = ref None in 
    (fun x -> match !cache with 
     | Some y -> y 
     | None -> cache := Some x; x) 

それは異なっています。 rememberはまだその機能を果たしていますが、そのコンテンツを定義する実際の部分は(fun x -> match ...)です。これにはcacheが含まれ、キャッシュは一度初期化され、一度だけになります。従ってcacheは将来の間に共有されますremember呼び出し。