Y 或 Z 组合器

尽管 Julia 不是一种纯函数式语言,但它完全支持函数式编程的许多基石:一流函数 ,词法范围和闭包

定点组合子是在功能的编程的关键组合子。因为朱莉娅有着急切的评价语义(正如许多函数式语言,包括 Julia 深受启发的 Scheme),Curry 的原始 Y-combinator 不会开箱即用:

Y(f) = (x -> f(x(x)))(x -> f(x(x)))

然而,Y 组合子 Z-combinator 的近亲确实会起作用:

Z(f) = x -> f(Z(f), x)

这个组合器接受一个函数并返回一个函数,当用参数 x 调用时,它将自己传递给 x。为什么函数自身传递会有用?这允许递归而不实际引用函数的名称!

fact(f, x) = x == 0 ? 1 : x * f(x)

因此,Z(fact) 成为阶乘函数的递归实现,尽管在此函数定义中没有可见的递归。 (当然,递归在 Z 组合器的定义中很明显,但这在一种急切的语言中是不可避免的。)我们可以验证我们的函数确实有效:

julia> Z(fact)(10)
3628800

不仅如此,它的速度与我们对递归实现的预期一样快。LLVM 代码演示了将结果编译为普通旧分支,减去,调用和乘法:

julia> @code_llvm Z(fact)(10)

define i64 @"julia_#1_70252"(i64) #0 {
top:
  %1 = icmp eq i64 %0, 0
  br i1 %1, label %L11, label %L8

L8:                                               ; preds = %top
  %2 = add i64 %0, -1
  %3 = call i64 @"julia_#1_70060"(i64 %2) #0
  %4 = mul i64 %3, %0
  br label %L11

L11:                                              ; preds = %top, %L8
  %"#temp#.0" = phi i64 [ %4, %L8 ], [ 1, %top ]
  ret i64 %"#temp#.0"
}