Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/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
Clojure Frege是否执行尾部调用优化?_Clojure_Functional Programming_Jvm_Jvm Languages_Frege - Fatal编程技术网

Clojure Frege是否执行尾部调用优化?

Clojure Frege是否执行尾部调用优化?,clojure,functional-programming,jvm,jvm-languages,frege,Clojure,Functional Programming,Jvm,Jvm Languages,Frege,是否在弗雷格对尾部呼叫进行了优化。我知道,Java和编译成JVM字节码的语言(如Clojure和Scala)中都没有TCO。Frege呢?Frege通过简单地生成while循环来进行尾部递归优化 一般的尾部调用都是通过懒惰“顺便”处理的。如果编译器看到对已知(间接)递归的可疑函数的尾部调用,则返回延迟结果(thunk)。因此,调用该函数的真正负担在于调用方。这样就避免了深度取决于数据的堆栈 也就是说,在函数式语言中,静态堆栈深度本质上已经比Java更深。因此,一些程序需要有一个更大的堆栈(即使用

是否在弗雷格对尾部呼叫进行了优化。我知道,Java和编译成JVM字节码的语言(如Clojure和Scala)中都没有TCO。Frege呢?

Frege通过简单地生成while循环来进行尾部递归优化

一般的尾部调用都是通过懒惰“顺便”处理的。如果编译器看到对已知(间接)递归的可疑函数的尾部调用,则返回延迟结果(thunk)。因此,调用该函数的真正负担在于调用方。这样就避免了深度取决于数据的堆栈

也就是说,在函数式语言中,静态堆栈深度本质上已经比Java更深。因此,一些程序需要有一个更大的堆栈(即使用-Xss1m)

有些病理情况下,会生成大Thunk,当对它们进行评估时,会发生堆栈溢出。一个臭名昭著的例子是foldl函数(与Haskell中的问题相同)。因此,Frege中的标准左折叠是fold,它在累加器中是尾部递归且严格的,因此在恒定的堆栈空间中工作(如Haskells foldl')

以下程序不应堆栈溢出,但应在2或3秒后打印“false”:

module Test
    -- inline (odd) 
  where

even 0 = true
even 1 = false
even n = odd (pred n)

odd n = even (pred n)

main args =  println (even 123_456_789)
其工作原理如下:println必须有一个要打印的值,因此尝试求值(偶数n)。但它所得到的只是一声(奇数(pred n))。因此,它尝试评估这个thunk,从而得到另一个thunk(偶数(pred(pred n)))。偶数必须求值(pred(pred n))以查看参数是0还是1,然后返回另一个thunk(奇数(pred(n-2)),其中n-2已经求值。 这样,所有的调用(JVM级别)都是在println中完成的。任何时候都不会真正调用odd,反之亦然

如果取消内联指令的注释,则会得到偶数的尾部递归版本,并且获得的结果要快十倍

不用说,这个笨拙的算法只是为了演示——通常人们会用位运算检查均匀性

下面是另一个版本,它是病态的,将导致堆栈溢出:

even 0 = true
even 1 = false
even n = not . odd  $ n
odd    = even . pred
这里的问题是,
not
是尾部调用,它的参数很严格(即,要否定某个东西,必须先得到该东西)。因此,当计算
偶数n
时,则
not
必须完全计算
奇数n
,反过来,必须完全计算
偶数(pred n)
因此需要2*n个堆栈帧


不幸的是,即使JVM有一天应该有适当的尾部调用,这种情况也不会改变。原因是严格函数参数中的递归。

你的问题的标题是人们看到的第一件事,“TCO”只是另一个TLA。应该提到的是Scala有TCO,一些JVM(如IBM)也有TCO也要实现它。@Landei这是Scala中的一个新功能吗?很长一段时间以来Scala都不支持TCO!IIRC,Scala从一开始就支持TCO(简单的例子)。试试
def foo{println(“foo!”);foo}
-如果你调用它,它不会停止使用
StackOverflowException
。惊人的回答,非常感谢!顺便问一下,Frege中有严格的注释吗?