2016-10-14 9 views
4

私はリーダーモンスター、モンスターモナドまたはモナドモナドの仕組みを理解していますが、継続モナドでは苦労しています。以下のような 例として、私の頭を吹く継続モナドは実際にどのように働くのですか

type ContinuationMonad() = 
    member this.Bind (m, f) = fun c -> m (fun a -> f a c) 
    member this.Return x = fun k -> k x 

私は私の問題は、私は(>続き<「Tのような)継続のためのモナドのタイプであるものを手に入れることができないとどのように私はそれをアンラップして戻ってラップすることができますということだと思います。 有用な例やリンクがあれば幸いです。

+3

これは[こちら]偉大な長さで覆われている(http://stackoverflow.com/questions/3322540/how-and-why-does-the-haskell-cont:完成bind関数は、したがって、このようになります-monad-work)、特に@C。 A.マッキャンの答えは注目に値する(恐らくは2回読んだり)。 – scrwtp

答えて

10

私は他のところで言われたことを繰り返さないでしょう - コメントに言及された投稿は、継続モナドに関する多くの詳細を与えます。しかし、役立つかもしれない一つのことはCont<'T>のための明示的な定義を使用してコードスニペットを書き換えることである:

type Cont<'T> = 
    Cont of (('T -> unit) -> unit) 

タイプCont<'T>は計算を表します。 となります。結果を受け取り、何か(例えば、それを印刷します)を実行する関数'T -> unitを与えます。起動すると、unitが返され、(ある時点で)値'Tが生成され、という連続番号が返されます。このより明確な定義に

、ビルダーのように定義することができる。Return部材は、継続kを与え、演算を作成することx値と直ちに、この継続を呼び出す

type ContinuationMonad() = 
    member this.Bind (ma, f) = 
     Cont(fun k -> 
     let (Cont ca) = ma 
     ca (fun a -> 
      let (Cont cb) = f a 
      cb k)) 

    member this.Return x = 
     Cont(fun k -> k x) 
  • 私たちは帰ってきた。

  • Bindメンバは、継続が与えられたときにkという計算がmで始まる新しい計算を返します。この計算で値がaになると、関数fが呼び出されます。は、fの返り値を元の継続値k(最終結果で最終的に呼び出される「最後」の継続値)で呼び出します。

+0

モナド初心者のおかげで、これは私を助けました。私はそれを少し下に広げた。 – brianberns

1

私はいくつかの重要な注意点と、トーマスの答えが役に立ったと評価:それは示唆しているので、計算を表現するために名前Contを使用し

  • は私見Contがcontinationであることを(間違って) を混乱さ。 I 「不完全」計算を表しているので、代わりにIncという名前を使用することを提案します。この計算には、続行に渡す準備ができている値(タイプ 'T)が含まれています。 重要ポイントIncは継続と同じものではありません。

  • また、のパターンマッチングなしで、識別された共用体のパターンがないと、Incを定義することを提案します。これにより、 のBindが大幅に簡略化されます。我々は継続が常に がunitを生成することを前提とすべき理由

  • は私もわからないんだけど、それは確かにそう 、私は以下ではこの仮定しておこう、かなり物事を簡素化します。

だから、私たちは'T -> unitの署名を持つ任意の関数としての継続を定義することができ、私たちのようにIncを定義することができます。英語では

type Inc<'T> = 
    ('T -> unit) -> unit 

Incが与えられたにそのラップ'T値を渡します結果としてunitとなります。

次に、Bind関数の明示的な署名が必要です。それはモナドなので、我々はそれがこのように見えるように持って知っている:

let bind (inc : Inc<'T>) (wrap : 'T -> Inc<'U>) : Inc<'U> = 

のでbindは(タイプ'Tの)不完全な計算を取り、(タイプの不完全な計算で生の値を「ラップ」できる機能)、その型の新しい不完全計算を返します。このシグネチャに基づいて、bindIncを返す必要があり、Incは入力を継続する関数であることがわかります。だから我々はbindの実装は次のように開始する必要があることを知っている:

fun (cont : 'U -> unit) -> ... 

私たちの仕事は、与えられたIncの内側に包まれています'T値を抽出して、与えられたラッパー関数を使用して、それを再ラップすることです。 重要な洞察:この値を取得するには、Incに今すぐ書き込む続きを渡すよう依頼するしかありません。この「人工的な」続きの中で、抽出された値を再ラップし、それを呼び出し側に返します。

let bind (inc : Inc<'T>) (wrap : 'T -> Inc<'U>) : Inc<'U> = 
    fun (cont : 'U -> unit) -> // return an Inc, which is a function that takes a continuation as input 
     inc (fun t ->   // force the incomplete computation to cough up its wrapped value 
      (wrap t) cont)  // wrap the raw value so it can be sent to the given continuation 
関連する問題