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)推理问题。- 在 OP 的第二个地图示例中,我发现它由于v值的推断问题而无法编译,因为它推断fa -> b list,而不是所需的a -> b。为什么它以这种方式推断?万一let v = f x它会很好地推断出来。

3)在我看来,VS 在工具提示中显示了不准确的类型签名:monad 的 Return 的返回类型为:('e->'f)->f,而 Bind 的返回类型仅为'c->'b。- 似乎它('e->'f)c在 Bind 情况下简化,或者我在这里遗漏了什么?

谢谢你的澄清,
托马斯

编辑 - 测试转储:

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被延迟,直到实际应用结果函数。这是防止堆栈溢出的关键区别。

关于你的其他问题,我不太清楚你在第二个问题中要问什么。对于您的第三个问题,编译器已推断出Bind. 没错,您可能期望的传统类型比这更具体,但是您可以Bind在比严格必要的更广泛的上下文中调用它并不是一个真正的问题。如果你真的想要一个更具体的类型,你总是可以添加注释来约束签名。

于 2013-07-22T16:23:58.583 回答