7

OCamlの弱いポリモーフィズムについて少し混乱しています。

関数を定義する次のスニペットを参照してくださいremember

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

コンパイラは多相型を推論でき、'a -> 'aローカルcacheで使用されます。

しかし、上記のコードを次のように変更すると

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

コンパイラは弱ポリモーフィック型'_a -> '_aを推論します。また、それはcacheの呼び出し間で共有されているようですremember

なぜコンパイラはここで弱いポリモーフィック型を推論し、なぜcache共有されているのですか?

さらに、コードを再度変更すると

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

コンパイラはポリモーフィック型'a -> 'a -> 'aを推測し、cacheローカルで使用されるようになります。これはなぜですか?

4

3 に答える 3

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

ここでcacheは、返された関数によって閉じられます。しかし、 を宣言する時点ではcache、型がどうなるかについての情報はありません。xの型が何であるかによって決定され、が定義さcacheれたときに作成されます。remember

しかし、これはクロージャであるため、次のようなことができます。

> remember 1
  1

cache : int option ref実際に何かを保存したので、これは明らかです。は1 つしかないため、1 つのcacheタイプrememberしか保存できません。

x次のものでは、2 つ以上のものを閉じますcache。型の呼び出しごとに新しいcacherefを作成するため、remember再び完全にポリモーフィックになる可能性があります。型が弱ポリモーフィックではない理由は、そこに格納することを知っており、が作成された時点で s 型xを持っているためです。xcache

于 2013-07-29T01:13:58.447 に答える
6

これは、値の制限に関係しているようです。完全な値の制限 (SML など) では、コードが完全に拒否されます。弱いポリモーフィック型は、Jacques Garrigue による論文「Relaxing the Value Restriction」で説明されています。これは、あなたの質問を読んだ後に偶然見つけたものです。

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

呼び出し間で共有されるという事実cacheは、ML コードが何を意味するかについての正しいメンタル モデルを持っている場合は明らかです。rememberとの 2 つの値を定義していcacheます。ネスティングは単にスコープをcacheブロックに private にするだけです。

于 2013-07-29T01:05:17.060 に答える
1
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)

上記の 2 つのバージョンでrememberは、 は「直接」関数であり、 のように呼び出すたびremember 1に に初期化cacheされref Noneますね。したがって、実際には何も記憶せず、呼び出しcache間で共有されません。remember


他のバージョンでは:

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

于 2014-10-11T11:40:51.853 に答える