はい、これは基本的に動作し、ハスケルはどのように動作しますか。しかし、ヒッチがあります:リファレンスが決してモナドを "エスケープ"しないようにする必要があります。擬似コード:
module MutMonad : sig
(* This is all sound: *)
type 'a t
type 'a ref
val mkref : 'a -> ('a ref) t
val read_ref : 'a ref -> 'a t
val write_ref : 'a -> 'a ref -> unit t
(* This breaks soundness: *)
val run : 'a t -> 'a
end
我々はスタート地点の実行の有無がすぐに戻って私たちを取得します。
let x = run (mkref []) in (* x is of type ('a list) ref *)
run (read_ref x >>= fun list -> write_ref (1::list) x);
run (read_ref x >>= fun list -> write_ref (true::list) x)
Haskellは2つの方法で回避します:main
が既にモナドのタイプ(あるので
- IO)、それはちょうどがないrun0または同様のを持つことができます。
- STモナドは、モナドが一度終了するとリファレンスが使用不能になるようにランク2タイプのトリックを使用し、サウンドを残しながらローカルに変更可能な状態を可能にします。あなたが何か持っている後者の場合については
:タイプレベルで
module MutMonad : sig
(* The types now take an extra type parameter 's,
which is a phantom type. Otherwise, the first
bit is the same: *)
type 'a 's t
type 'a 's ref
val mkref : 'a -> ('a 's ref) 's t
val read_ref : 'a 's ref -> 'a 's t
val write_ref : 'a -> 'a 's ref -> unit 's t
(* This bit is the key. *)
val run : (forall 's. 'a 's t) -> 'a
end
forall 's. ...
はfun x -> ...
に似ています。の変数はローカルにバインドされているので、実行する引数は何も想定できません。実行するための引数は、それらが's
ための同じタイプを渡されることを前提とすることはできませんので
let old_ref = run (mkref 3) in
run (read_ref old_ref)
:特に、これはチェックを入力しないであろう。
これには、ocamlには存在しない型システムの機能が必要であり、Haskellではlangugae拡張子(Rank2Types)が必要です。
詳細な回答をいただきありがとうございます。それと同時に、私は 'runST'とその必要性に出くわしましたが、健全性を保証するかどうかは不明でした。関心のある読者は、[this](https://stackoverflow.com/questions/39725024/runst-with-hindley-milner-type-system)関連の質問もチェックすることができます。 – max