2011-12-16 137 views
2

我试图掌握延续传球风格(CPS),因此我刚刚改造了Gary Short向我展示的一个例子。我没有他的示例源代码,所以我试图从内存中重写他的示例。考虑下面的代码:如何在CPS中编写此代码?

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 - 更不用提,它似乎真的哈克而且有相当多的重复代码,这也似乎是一个代码味道的事实。

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

+0

你能使用的计算式?或者这不符合CPS标准? – Shlomo 2011-12-16 17:43:23

+0

@ Shlomo - 这不是一个坏建议,但它是把马车放在马前。我试图掌握CPS,因为CPS是计算表达式结构的一部分。 – 2011-12-16 17:51:59

回答

3

简单的方法:

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

这是由克里斯·史密斯 “编程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)))) 
+0

感谢您的参考;我有克里斯史密斯的书,所以我会读它的一部分。 – 2011-12-16 17:53:28

2

使用也许单子定义here

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