哪些语言支持*递归*函数文字/匿名函数?
现在似乎有不少主流语言支持函数文字。它们也被称为匿名函数,但我不在乎它们是否有名称。重要的是函数文字是一个表达式,它产生一个尚未在别处定义的函数,因此例如在C中,
&printf
不计算。
编辑添加:如果你有一个真正的函数文字表达式<exp>
,你应该能够将它传递给函数f(<exp>)
或立即将它应用于一个参数,即。 <exp>(5)
。
我很好奇哪些语言可以让你编写递归的函数文字。维基百科的“匿名递归”文章没有给出任何编程示例。
我们以递归因子函数为例。
以下是我所知道的:
JavaScript / ECMAScript可以用callee
完成:
function(n){if (n<2) {return 1;} else {return n * arguments.callee(n-1);}}
使用letrec
的语言很容易,例如Haskell(称之为let
):
let fac x = if x<2 then 1 else fac (x-1) * x in fac
Lisp和Scheme中有等价物。请注意,fac
的绑定对于表达式是局部的,因此整个表达式实际上是一个匿名函数。
还有其他人吗?
没有找到相关结果
已邀请:
16 个回复
逆捐凶撤小
莽缓逢
瞥同忙接
区块不是绝对必要的;我把它包括在内以强调结果是一个真正的匿名函数。
替秀宝
)和Scheme(
)之外,JavaScript还允许你命名一个匿名函数:
这比使用
更方便。 (这与顶层的
不同;后者会导致名称出现在全局范围内,而在前一种情况下,名称仅出现在函数本身的范围内。)
冕偷淮款
钨蜡唤喉晤
外镶受继
这也可以写成:
在这两种情况下,它都是函数文字。但请注意,在第二个示例中,名称未添加到周围范围 - 这可能会造成混淆。但这并没有被广泛使用,因为一些javascript实现不支持这个或有一个错误的实现。我还读到它的速度较慢。 匿名递归又有所不同,当函数在没有引用自身的情况下进行递归时,Y Combinator已被提及。在大多数语言中,没有必要使用更好的方法。这是一个javascript实现的链接。
呕蹿尉
我想我听说有传言说C#团队正在考虑修改明确赋值的规则,以使单独的声明/初始化变得不必要,但我不会发誓。 每种语言/运行时环境的一个重要问题是它们是否支持尾调用。在C#中,据我所知,MS编译器不使用
IL操作码,但JIT可能会在某些情况下优化它。显然,这很容易使工作程序和堆栈溢出之间产生差异。 (对此进行更多控制和/或保证何时会发生这种情况会很好。否则,在一台机器上运行的程序可能会以难以理解的方式在另一台机器上运行。) 编辑:正如FryHard所指出的,这只是伪递归。简单到足以完成工作,但Y-combinator是一种更纯粹的方法。我在上面发布的代码还有另一个警告:如果你改变
的值,任何试图使用旧值的东西都会失败,因为lambda表达式已经捕获了
变量本身。 (当然,为了正常工作,它必须......)
撵穆
这是一个匿名函数,从x倒计时然后返回1.它不是很有用,因为Matlab缺少?:运算符并且不允许在匿名函数中使用if-blocks,因此很难构造基本情况/递归步骤形式。 您可以通过调用f(-1)来证明它是递归的;它将倒数到无穷大并最终抛出最大递归错误。
并且您可以直接调用匿名函数,而不将其绑定到任何变量,直接将其传递给feval。
为了使其有用,您可以创建一个单独的函数来实现递归步骤逻辑,使用“if”来保护递归案例不受评估。
鉴于此,这是阶乘。
你可以无约束地调用它。
熊融炭臀陛
定义递归函数来表示函数本身,如:
例如一个阶乘:
这与符号
一致,以引用第i个参数,以及脚本是其自己的第0个参数的shell脚本约定。
乏摩纶誊伟
死搭胯
使用:
拟僚疽刊剔
渐首洽陈染
辰炔诚薯
这样:
评估一个真正的匿名递归因子函数,例如可以使用如下:
然而,让它匿名的真正原因是,如果我这样做:
该函数后来从内存中清除,没有范围,因此在此之后:
将发出错误信号,或者将被绑定到以前绑定的任何f。 在Haskell中,实现相同的特殊方法是:
差别在于这个函数没有作用域,如果我不使用它,Haskell是Lazy,效果与空行代码相同,它是真正的文字,因为它与C代码具有相同的效果:
字面数字。即使我之后立即使用它也会消失。这是文字函数的意义,而不是运行时本身的创建。
舜辉
专门为此目的采用了一个可选名称(名称不会超出定义范围):
如果恰好是尾递归,则
是一种更有效的方法: