Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 组合多个函数时堆栈溢出_F#_Stack Overflow_Tail Recursion_Continuations - Fatal编程技术网

F# 组合多个函数时堆栈溢出

F# 组合多个函数时堆栈溢出,f#,stack-overflow,tail-recursion,continuations,F#,Stack Overflow,Tail Recursion,Continuations,下面是一种展平二叉搜索树的方法。它的问题是,当它构建的大型函数最终应用于[]时,堆栈溢出。我想知道是否有一种合理的方法可以在不完全改变其工作方式的情况下修复此代码片段。例如,如果构建一个自定义编写器来构建一个函数树,然后使用显式堆栈对其求值(因为问题已经是展平一棵树),这将无助于取得进展 树展平函数不是尾部递归函数 函数的组合不是尾部递归的。这很容易通过展开您的三重组合看到: original: fl << cons << fr unfold c

下面是一种展平二叉搜索树的方法。它的问题是,当它构建的大型函数最终应用于[]时,堆栈溢出。我想知道是否有一种合理的方法可以在不完全改变其工作方式的情况下修复此代码片段。例如,如果构建一个自定义编写器来构建一个函数树,然后使用显式堆栈对其求值(因为问题已经是展平一棵树),这将无助于取得进展


树展平函数不是尾部递归函数

函数的组合不是尾部递归的。这很容易通过展开您的三重组合看到:

original:              fl << cons << fr
unfold compositions:   fun a -> fl (cons (fr a))
unfold nested calls:   fun a ->
                          let x = fr a
                          let y = cons x
                          fl y
原件:fl
设x=fr a
设y=x
弗利
如您所见,此函数首先调用
fr
,然后对其结果执行一些非常重要的操作。最后一个对
fl
的调用是尾部递归的,但前两个不是。当执行
fr
cons
时,返回地址需要保留在堆栈上,这是无法避免的

这不是尾部递归。尾部递归的工作原理是将最后一次调用的结果传递给堆栈上的调用方。将这个结果作为参数传递给另一个函数——这是完全不同的事情

至于如何修复它——如果你坚持使用函数组合,你就不能。如果你不坚持,那么你已经有了解决办法

就你设计的例子而言-我认为它失败了,因为你在FSI或类似的东西中运行它。我刚才已经核实了:

  • 如果您正常编译它,它工作得很好
  • 如果关闭优化,则会导致堆栈溢出
  • 如果将
    id
    替换为一些非尾部递归函数(例如
    funx->x+1
    ),它也会失败

您是否在进行优化编译?你的运行时间是什么?操作系统?我没有使用优化,因为我不想要一个有时有效有时无效的解决方案。然而,我正在生成尾部调用。我正在Windows下使用.net。我知道在Mono下不能正确实现尾部调用,但这不是问题所在。非常感谢。我认为人为的例子失败的原因与非平凡的例子完全相同,只是优化器可以在某些情况下发挥作用。你的答案的关键部分是说“没办法”。我认为这可能是对的,因为使用尾部递归通常是一件痛苦的事情,尽管我们两人的意思都不是简单的方法。除了生成的解决方案不如替代方案之外,没有什么可以阻止使用嵌套的延续。如果没有人提供令人惊讶的见解,我将接受你的回答。再次感谢
let test_composition () =
   let mutable f = id
   for i=0 to 1000000 do
       f <- id << f // >> works fine for me
   printf "Functions return %d" (f 123)
 let flatten t =

    let rec f t acc cont =
        match t with
        | Leaf ->
            cont acc

        | Bin (l, x, r) ->
            f r acc (fun rs -> f l (x::rs) cont)

    f t [] id
original:              fl << cons << fr
unfold compositions:   fun a -> fl (cons (fr a))
unfold nested calls:   fun a ->
                          let x = fr a
                          let y = cons x
                          fl y