F# 延续出现 StackOverflowException

发布于 2024-11-30 05:56:28 字数 877 浏览 2 评论 0原文

大家好,我正在实现一个 F# 函数,它采用两个类型的列表:(int*float) 列表。这两个列表的长度不同。 这对的int元素是一个递增的代码。 我想做的是创建一个新列表,其中包含两个具有相同代码的列表中每两个元素的 (int*float) 。需要注意的是,列表中的代码是按递增顺序排列的。 这些列表可能有点长,比如 2-3000 个元素,所以我尝试使用连续传递风格来实现这个函数,以避免 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

我做错了什么吗?

Hi guys I'm implementing an F# function that takes two lists of type : (int*float) list. These two lists have different lentgths.
The int element of the couple is an increasing code.
What I wanted to do is create a new list that will contain a couple (int*float) for each two elements of the two lists that have the same code. It's important to note that codes in lists are in increasing order.
These lists are probably a little long, like 2-3000 elements., so I tried to implement this function using continuation passing style in order to avoid StackOverflowExceptions. but sadly i failed.

This is the function, i hope you will give me any hints!

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

I've done something wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一梦等七年七年为一梦 2024-12-07 05:56:28
(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

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

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

should be

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

to make it tail-recursive:

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

This will also fix your results being returned in reverse order.

半岛未凉 2024-12-07 05:56:28

问题出在这一行

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

这里你调用延续,但这个调用不是尾部,因为你仍然需要 cons (code,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 []

The problem lies in this line

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

Here you invoke continuation but this call is not tail because you still need to cons (code,Math.Abs(rate-rate2)) to the result of (k c)

I guess you can build result list from the inside out and just reverse final result:

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

EDIT:
after second look I think CPS is not needed here and using accumulator should do the trick:

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 []
甚是思念 2024-12-07 05:56:28

对于替代答案,请看一下: http://fssnip.net/75

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

该函数实际上在较大的代码片段中使用: http://fssnip.net/76

For an alternative answer, take a look at this: http://fssnip.net/75

The function takes a couple of sequences and returns pairs which match according to some matching function. I haven't volume-tested it.

The function is actually used in the larger snippet here: http://fssnip.net/76

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文