【问题标题】:How To Write This In CPS?如何在 CPS 中编写此内容?
【发布时间】:2011-12-16 17:29:28
【问题描述】:

我正在尝试掌握连续传球风格 (CPS),因此我正在修改 Gary Short 很久以前向我展示的示例。我没有他的示例源代码,所以我试图从内存中修改他的示例。考虑以下代码:

let checkedDiv m n =
    match n with
    | 0.0 -> None
    | _ -> Some(m/n)

let reciprocal r = checkedDiv 1.0 r

let resistance c1 c2 c3 =
     (fun c1 -> if (reciprocal c1).IsSome then 
        (fun c2 -> if (reciprocal c2).IsSome then
            (fun c3 -> if (reciprocal c3).IsSome then 
                Some((reciprocal c1).Value + (reciprocal c2).Value + (reciprocal c3).Value))));;

我不太明白如何构造阻力函数。我之前想出了这个:

let resistance r1 r2 r3 =
        if (reciprocal r1).IsSome then
            if (reciprocal r2).IsSome then
                if (reciprocal r3).IsSome then
                    Some((reciprocal r1).Value + (reciprocal r2).Value + (reciprocal r3).Value)
                else
                    None
            else
                None
        else
            None 

但是,当然,这并没有使用 CPS——更不用说它看起来很 hacky 并且有相当多的重复代码,这也似乎是代码的味道。

有人可以告诉我如何以 CPS 方式重写阻力函数吗?

【问题讨论】:

  • 你会使用计算表达式吗?还是不符合 CPS 标准?
  • @Shlomo——这不是一个坏建议,但它有点本末倒置。我正在努力掌握 CPS,因为 CPS 是计算表达式结构的一部分。

标签: f# continuation-passing


【解决方案1】:

直截了当:

let resistance_cps c1 c2 c3 = 
    let reciprocal_cps r k = k (checkedDiv 1.0 r)
    reciprocal_cps c1 <| 
        function
        | Some rc1 -> 
            reciprocal_cps c2 <| 
                function
                | Some rc2 -> 
                    reciprocal_cps c3 <|
                        function 
                        | Some rc3 -> Some (rc1 + rc2 + rc3)
                        | _ -> None
                | _ -> None
        | _ -> None

或者用 Option.bind 稍微短一点

let resistance_cps2 c1 c2 c3 = 
    let reciprocal_cps r k = k (checkedDiv 1.0 r)
    reciprocal_cps c1 <|
        Option.bind(fun rc1 -> 
            reciprocal_cps c2 <| 
                Option.bind(fun rc2 ->
                    reciprocal_cps c3 <| 
                        Option.bind(fun rc3 -> Some (rc1 + rc2 + rc3))
                )
        )

【讨论】:

    【解决方案2】:

    这是 Chris Smith 的“Programming F#”一书中的一个已知任务; CPS 风格的解决方案代码在第 244 页上给出:

    let let_with_check result restOfComputation =
        match result with
        | DivByZero -> DivByZero
        | Success(x) -> restOfComputation x
    
    let totalResistance r1 r2 r3 =
        let_with_check (divide 1.0 r1) (fun x ->
        let_with_check (divide 1.0 r2) (fun y ->
        let_with_check (divide 1.0 r3) (fun z ->
        divide 1.0 (x + y + z) ) ) )
    

    【讨论】:

    • 感谢参考;我有 Chris Smith 的书,所以我会读它的那一部分。
    【解决方案3】:

    使用定义的 Maybe monad here

    let resistance r1 r2 r3 =
      maybe {
        let! r1 = reciprocal r1
        let! r2 = reciprocal r2
        let! r3 = reciprocal r3
        return r1 + r2 + r3
      }
    

    【讨论】:

    • 这不是一个坏建议,但我正在努力理解单子,理解 CPS 是理解单子的一部分。
    • 那么也许一个有用的练习就是通过查看Bind的定义来减少它的糖分。
    猜你喜欢
    • 2012-04-24
    • 2019-12-17
    • 1970-01-01
    • 2011-03-21
    • 2019-02-07
    • 1970-01-01
    • 2015-09-28
    • 2019-10-29
    • 2019-01-18
    相关资源
    最近更新 更多