这是对此的参考问题:StackOverflow in continuation monad
与我一起玩了一点,需要一些澄清。
1)我想这个:
member this.Delay(mk) = fun c -> mk () c
使得计算工作流程中的行为能够实现这一点之间的差异:
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)推理问题。 - 在OP的第二个地图示例中,我发现它由于v
值的推理问题而无法编译,因为它将f
推断为a -> b list
,而不是期望的a -> b
。为什么以这种方式推断?如果let v = f x
它会很好地推断出来。
3)在我看来,VS在工具提示中显示不准确的类型签名:
返回类型的monad的返回值为:('e->'f)->f
,而Bind的返回类型仅为'c->'b
。 - 在Bind案例中它似乎只将('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
答案 0 :(得分:3)
问题恰恰在于fun c -> map xs c
与map xs
相同。它们在某种意义上具有相同的“含义”,但它们的运行时语义不同。在后一种情况下,计算表达式会导致立即调用map
函数,并将xs
作为参数(返回另一个函数作为结果)。另一方面,评估fun c -> map xs c
不会会立即调用map
!对map
的调用会延迟,直到实际应用生成的函数。这是防止堆栈溢出的关键区别。
关于你的其他问题,我在你的第二个问题中找不到你所问的内容。对于第三个问题,编译器推断出Bind
可能的最一般类型。你是对的,你可能期望的传统类型比这更具体,但是你可以在更广泛的上下文中调用Bind
并不是一个真正的问题。如果你真的想要一个更具体的类型,你总是可以添加注释来约束签名。