List F#continuations继续执行StackOverflowException
大家好,我正在实现一个F#函数,它接受两个类型的列表:(int*float)list。这两个列表有不同的长度。 耦合的int元素是一个递增的代码。 我想做的是创建一个新的列表,它将为两个具有相同代码的列表中的每两个元素包含一对(int*float)。需要注意的是,列表中的代码顺序是递增的。 这些列表可能有点长,比如2-3000个元素,所以我尝试使用延续传递样式来实现这个函数,以避免StackOverflowException。但遗憾的是我失败了 这是函数,希望你能给我一些提示List F#continuations继续执行StackOverflowException,list,f#,continuations,stack-overflow,List,F#,Continuations,Stack Overflow,大家好,我正在实现一个F#函数,它接受两个类型的列表:(int*float)list。这两个列表有不同的长度。 耦合的int元素是一个递增的代码。 我想做的是创建一个新的列表,它将为两个具有相同代码的列表中的每两个元素包含一对(int*float)。需要注意的是,列表中的代码顺序是递增的。 这些列表可能有点长,比如2-3000个元素,所以我尝试使用延续传递样式来实现这个函数,以避免StackOverflowException。但遗憾的是我失败了 这是函数,希望你能给我一些提示 let ident
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,因为您仍然需要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 []
问题就在这方面
produceResult (xs, ys) (fun c -> (code,Math.Abs(rate-rate2))::(k c))
这里您调用continuation,但这个调用不是tail,因为您仍然需要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 []
应该是
(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 -> 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
这也将修复以相反顺序返回的结果。要获得替代答案,请查看以下内容: 该函数获取一对序列并返回根据某个匹配函数匹配的对。我还没有对它进行体积测试
该函数实际上在此处较大的代码段中使用:要获得替代答案,请查看以下内容: 该函数获取一对序列并返回根据某个匹配函数匹配的对。我还没有对它进行体积测试
该函数实际上在这里的较大代码段中使用:实际上,通过这些修改,我得到了与以前一样的StackOverflowException。这有点奇怪,因为我以相同的方式实现了它,用于略有不同的任务(一个函数使用两个有序整数列表生成对应的列表),并且它在没有问题的情况下进行尾部递归。我刚刚用两个各为1亿的列表进行了测试,没有得到堆栈溢出。我将列表增加到10亿并耗尽了内存,但仍然没有堆栈溢出。我真的不知道Daniel,我已经完成了复制和粘贴,仍然有堆栈溢出。您可能正在调试模式下运行,这会禁用尾部调用。是的。项目属性>构建>检查生成尾部调用。实际上,通过这些修改,我得到了StackOverflowException。这有点奇怪,因为我以相同的方式实现了它,用于略有不同的任务(一个函数使用两个有序整数列表生成对应的列表),并且它在没有问题的情况下进行尾部递归。我刚刚用两个各为1亿的列表进行了测试,没有得到堆栈溢出。我将列表增加到10亿并耗尽了内存,但仍然没有堆栈溢出。我真的不知道Daniel,我已经完成了复制和粘贴,仍然有堆栈溢出。您可能正在调试模式下运行,这会禁用尾部调用。是的。项目属性>构建>检查生成尾部调用。使用累加器将以相反的顺序输出结果,他当前的实现也会这样做(我假设不是故意的)。使用累加器将以相反的顺序输出结果,他当前的实现也会这样做(我假设不是故意的)。