5

これは、これに対する参照の質問です: StackOverflow in continuation モナド
で、私が少し遊んだので、いくつかの説明が必要です。

1)私はこれを推測します:

member this.Delay(mk) = fun c -> mk () c

これらの間のtoyvoによって示されたように、計算ワークフローの動作に違いを生じさせます。

cBind (map xs) (fun xs -> cReturn (f x :: xs))  

cBind (fun c -> map xs c) (fun xs -> cReturn (f x :: xs))


(fun c -> map xs c)だから私はトリックが何であるかを正確に理解していません.(map xs)

2) 推論の問題。v- OP の 2 番目のマップの例では、 value の推論fの問題が原因でコンパイルされないことがわかりましa -> b lista -> b。なぜこのように推論するのでしょうか。let v = f xそれがうまく推論できる場合。

3) VS がツールチップに不正確な型シグネチャを表示しているように思えます: モナドの Return の戻り値の型は: です('e->'f)->fが、Bind の戻り値の型は のみ'c->'bです。-バインドの場合('e->'f)のみに単純化されているようですが、ここで何か不足していますか?c

明確にしてくれてありがとう、
トーマス

編集 - テストダンプ:

let cReturn x = fun k -> k x
let cBind m f = 
    printfn "cBind %A" <| m id
    fun c -> m (fun a -> f a c)

let map_fixed f xs =
  let rec map xs =
    printfn "map %A" xs
    match xs with
      | [] -> cReturn []
      | x :: xs -> cBind (fun c -> map xs c) (fun xs -> cReturn (f x :: xs)) 
  map xs (fun x -> x)

let map f xs =
  let rec map xs =
    printfn "map %A" xs
    match xs with
      | [] -> cReturn []
      | x :: xs -> cBind (map xs) (fun xs -> cReturn (f x :: xs)) 
  map xs (fun x -> x)

[1..2] |> map_fixed ((+) 1) |> printfn "%A"
[1..2] |> map ((+) 1) |> printfn "%A"

map_fixed:
マップ [1; 2] マップ [2] マップ [] cBind [] マップ [] cBind [3] マップ [2] マップ [] cBind [] マップ [] [2; 3]

マップ:
マップ [1; 2] マップ [2] マップ [] cBind [] cBind [3] [2; 3]

質問2に編集:

let map f xs =
    let rec map xs =
        cont {
            match xs with
            | [] -> return []
            | x :: xs ->
                let v = f x // Inference ok
                //let! v = cont { return f x } // ! Inference issue - question 2
                let! xs = map xs
                return v :: xs
        }
    map xs id
4

1 に答える 1

3

問題は、それが と同じでfun c -> map xs c はないということですmap xs。ある意味では同じ「意味」を持っていますが、実行時のセマンティクスは異なります。後者の場合、式を評価すると、引数としてmap関数が即座に呼び出されxsます (結果として別の関数が返されます)。一方、評価してもすぐに!が呼び出されるわけでfun c -> map xs c はありません。mapへの呼び出しmapは、結果の関数が実際に適用されるまで遅延されます。これは、スタック オーバーフローを防ぐ重要な違いです。

他の質問に関しては、2 番目の質問で何を求めているのかよくわかりません。3 番目の質問について、コンパイラは、可能な最も一般的な型を推測しましたBind。あなたが期待するかもしれない伝統的な型がこれよりも具体的であることは正しいですが、Bind厳密に必要なよりも広い一連のコンテキストで呼び出すことができることは、実際には問題ではありません。また、より具体的な型が本当に必要な場合は、いつでも注釈を追加して署名を制限できます。

于 2013-07-22T16:23:58.583 に答える