繁体   English   中英

F#continuations继续使用StackOverflowException

[英]F# continuations goes on StackOverflowException

大家好我正在实现一个F#函数,它接受两个类型列表:(int * float)list。 这两个列表有不同的lentgths。 这对夫妇的int元素是一个增加的代码。 我想要做的是为具有相同代码的两个列表的每两个元素创建一个包含一对(int * float)的新列表。 值得注意的是,列表中的代码按顺序递增。 这些列表可能有点长,比如2-3000个元素。所以我尝试使用continuation传递样式来实现这个函数,以避免StackOverflowExceptions。 但遗憾的是我失败了。

这是功能,我希望你能给我任何提示!

let identifiedDifference list1 list2 =
    let rec produceResult (l1, l2) k =
        match l1,l2 with
            | [],[] 
            | _,[]
            | [],_ -> k []
            | (code,rate:float)::xs, (code2,rate2)::ys -> 
                if code = code2 
                    then
                        produceResult (xs, ys) (fun c -> (code,Math.Abs(rate-rate2))::(k c))
                    elif code > code2
                        then produceResult (l1, ys) k
                        else produceResult (xs, l2) k
    produceResult (list1, list2) id

我做错了什么?

问题出在这一行

produceResult (xs, ys) (fun c -> (code,Math.Abs(rate-rate2))::(k c))

在这里你调用continuation但是这个调用不是tail,因为你仍然需要((代码,Math.Abs​​(rate-rate2))到(kc)的结果

我猜你可以从里到外构建结果列表,只是反转最终结果:

let identifiedDifference list1 list2 =
    let rec produceResult (l1, l2) k =
        match l1,l2 with
            | [],[] 
            | _,[]
            | [],_ -> k []
            | (code,rate:float)::xs, (code2,rate2)::ys -> 
                if code = code2 
                    then
                        produceResult (xs, ys) (fun c -> k((code,Math.Abs(rate-rate2))::c))
                    elif code > code2
                        then produceResult (l1, ys) k
                        else produceResult (xs, l2) k
    produceResult (list1, list2) List.rev

编辑:第二次看后我觉得这里不需要CPS,使用累加器应该可以解决问题:

let identifiedDifference list1 list2 = 
    let rec run l1 l2 acc = 
        match l1, l2 with
        | [], _ | _, [] -> List.rev acc
        | (code1, rate1 : float)::xs, (code2, rate2)::ys ->
            if code1 = code2 then
                run xs ys ((code1, abs (rate1 - rate2))::acc)
            elif code1 > code2 then
                run l1 ys acc
            else
                run xs l2 acc
    run list1 list2 []
(fun c -> (code,Math.Abs(rate-rate2))::(k c))

应该

(fun c ->  k ((code,Math.Abs(rate-rate2))::c))

使其尾递归:

let identifiedDifference list1 list2 =
    let rec produceResult (l1, l2) k =
        match l1,l2 with
            | [],[] 
            | _,[]
            | [],_ -> k []
            | (code,rate:float)::xs, (code2,rate2)::ys -> 
                if code = code2 then produceResult (xs, ys) (fun c ->  k ((code,Math.Abs(rate-rate2))::c))
                elif code > code2 then produceResult (l1, ys) k
                else produceResult (xs, l2) k
    produceResult (list1, list2) id

这也将修复以相反顺序返回的结果。

有关替代答案,请查看以下内容: http//fssnip.net/75

该函数采用几个序列并返回根据某些匹配函数匹配的对。 我还没有进行体积测试。

该函数实际上用于更大的片段: http//fssnip.net/76

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM