2013-07-22 81 views
5

這是一個參考問題是:StackOverflow in continuation monad
與我起了一點,就需要一些澄清。怎樣的延遲延續單子正好起到防止計算器?

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)推斷ence問題。 - 在OP的第二個地圖例子中,我發現它不會編譯,因爲v值的推理問題,因爲它推斷fa -> b list,而不是所需的a -> b。爲什麼它以這種方式推斷?在let v = f x的情況下,它會很好地推斷。

3)在我看來,VS顯示工具提示不準確的類型簽名:單子的收益 返回類型是:('e->'f)->f,而綁定的返回類型只'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] map [2] map [] 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 
+0

關於你的第二個問題,推論似乎對我很好。 – kvb

+0

如果我取消註釋// let!..它給了我:類型不匹配。期待一個'一個,但給了'一個列表 – tomasK

+0

我最後看到的錯誤 - 是在我的綁定定義 - 類似的日誌在第1點 - 愚蠢的我,感謝興趣。 – tomasK

回答

3

問題正是fun c -> map xs c一樣map xs。它們在某種意義上具有相同的「含義」,但它們的運行時語義不同。在後一種情況下,評估表達式會立即調用map函數,將xs作爲參數(返回另一個函數作爲結果)。在另一方面,評估fun c -> map xs c結果中map立即來電!到map該呼叫被推遲到實際應用所產生的作用。這是防止堆棧溢出的關鍵區別。

關於您的其他問題,我無法弄清楚您在第二個問題中提出的問題。對於第三個問題,編譯器已推斷出Bind可能的最普通類型。你說得對,你可能期望的傳統類型比這個更具體,但它不是一個真正的問題,你可以在更廣泛的背景下調用Bind。如果你真的想要一個更具體的類型,你總是可以添加註釋來限制簽名。

+0

關於我的第二個問題,當您嘗試編譯第二個op的函數時,會看到什麼問題 - 函數參數** f **的類型對我而言是意外的。 – tomasK

+0

- 「不會導致立即調用映射」 - 但根據我的測試轉儲它 - 在評估cBind之前 - 請參閱我的編輯... – tomasK

+1

@tomasK - 您的測試存在缺陷,因爲您正在應用「m '在記錄'cbind'時。將該行更改爲「printfn」cbind「',你會發現'map_fixed'確實延遲調用'map'。 – kvb