2013-07-22 29 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