Functional programming 具有连续性问题的F#扩展欧几里得算法

Functional programming 具有连续性问题的F#扩展欧几里得算法,functional-programming,f#,continuations,Functional Programming,F#,Continuations,我是F#的新手,从本科开始就没有做过函数式编程,但我一直在尝试自学。我编写了一个朴素的递归扩展欧几里德实现,它工作得很好,现在正在继续尝试 我用一个小例子手工浏览了两次代码,得到了正确的答案,但是当我通过解释器运行代码时,我没有得到相同的结果,所以我显然误解了我正在尝试做的事情 我手动运行eea 7 3,我计算的(正确)结果是(1,1,-2) 但是当我在解释器中运行它时 eea 7 3;; val it : int * int * int = (1, 0, 1) 以下是我的实现: let ee

我是F#的新手,从本科开始就没有做过函数式编程,但我一直在尝试自学。我编写了一个朴素的递归扩展欧几里德实现,它工作得很好,现在正在继续尝试

我用一个小例子手工浏览了两次代码,得到了正确的答案,但是当我通过解释器运行代码时,我没有得到相同的结果,所以我显然误解了我正在尝试做的事情

我手动运行eea 7 3,我计算的(正确)结果是(1,1,-2)

但是当我在解释器中运行它时

eea 7 3;;
val it : int * int * int = (1, 0, 1)
以下是我的实现:

let eea a b = 
    let rec contEEA a b f = 
        match b with
        | 0 -> f () (a,1,0)
        | _ -> 
            contEEA b (a%b) (fun () t ->
                let (d,x',y') = t
                (d, y', x'-(y'*(a/b)))
            )
    contEEA a b (fun () t -> t)
作为参考,直接来自教科书的幼稚方法是

let rec eea_gcd a b =
    match b with
    | 0 -> (a, 1, 0)
    | _ -> 
        let d, x', y' = eea_gcd b (a % b)
        (d, y', x'-(y'*(a/b)))

基于延续的版本总是只执行一次迭代(最后一次)。在进行递归调用时,continuation直接返回结果,而不是通过传递到上一个continuation将结果“返回”到上一个调用

因此,调用顺序如下所示:

  • eea 7 3
  • conteea73(fun()t->t)
  • b 0
    ==>第二种情况匹配
  • conteea31(fun()t->…(d,y',…)
  • b 0
    ==>第二种情况匹配
  • conteea10(fun()t->…(d,y',…)
  • b=0
    =>第一个案例匹配
  • 连续性被称为
    f()(1,1,0)
  • 继续计算结果
    (1,0,1-(0*(3/1))=(1,0,1)
    ,并立即返回它
  • 相反,您要做的是,当第一个continuation计算
    (1,0,1)
    的结果时,它应该将其传递给上一个continuation,以便它可以从那里继续计算,最终将结果传递给第一个continuation
    fun()t->t
    ,后者将其返回给使用者

    为此,请更换该行:

    (d, y', x'-(y'*(a/b)))
    
    为此:

    f (d, y', x'-(y'*(a/b)))
    

    另外,还有一些其他方面的注意事项。

  • continuation的第一个参数(单位,
    ()
    )不是必需的,因为它从未实际使用过(怎么可能?),您可能会丢失它

  • 删除unit参数后,第一个延续变为
    funt->t
    ,它有一个特殊的名称
    id
    (也称为“标识函数”)

  • 您可以在参数声明中正确地执行此操作,而不是使用
    let
    来分解三元组。参数可以是模式

  • 应用以上所有内容以及实际的问题修复,这里有一个更好的版本:

    let eea a b = 
        let rec contEEA a b f = 
            match b with
            | 0 -> f (a,1,0)
            | _ -> 
                contEEA b (a%b) (fun (d,x',y') -> 
                    f (d, y', x'-(y'*(a/b)))
                )
        contEEA a b id