How to do recursion in anonymous fn, without tail recursion
如何在不使用尾部递归的情况下在匿名函数中递归?
例如(摘自Vanderhart 2010,第38页):
1 2 3 4 5 | (defn power [number exponent] (if (zero? exponent) 1 (* number (power number (- exponent 1))))) |
假设我想作为匿名函数来执行此操作。由于某种原因,我不想使用尾递归。我该怎么办?例如:
1 2 | ( (fn [number exponent] ......))))) 5 3) 125 |
我可以为此使用循环,还是只能与recur一起使用?
1 2 | (doc fn) ;=> (fn name? [params*] exprs*) |
因此,添加" power"作为名称来完成您的示例。
1 2 3 4 | (fn power [n e] (if (zero? e) 1 (* n (power n (dec e))))) |
即使递归发生在尾部位置,也不会进行优化以替换当前的堆栈框架。 Clojure使用
我知道在Clojure中,语法支持"命名"一个匿名函数,正如其他答案所指出的那样。但是,我想展示一种解决该问题的第一原理方法,该方法不依赖于编程语言上是否存在特殊语法,并且可以在具有一阶过程(lambda)的任何语言上使用。
原则上,如果要进行递归函数调用,则需要引用该函数的名称,以使"匿名"(即,无名函数)不能用于执行递归……除非您使用Y组合器。这是它在Clojure中如何工作的解释。
让我通过示例向您展示它的用法。首先,
1 2 3 4 5 | (defn Y [f] ((fn [x] (x x)) (fn [x] (f (fn [& args] (apply (x x) args)))))) |
现在,实现问题中定义的
1 2 3 4 5 | (fn [power] (fn [number exponent] (if (zero? exponent) 1 (* number (power number (- exponent 1)))))) |
最后,这是将
1 2 3 4 5 6 7 8 9 | ((Y (fn [power] (fn [number exponent] (if (zero? exponent) 1 (* number (power number (- exponent 1))))))) 5 3) > 125 |
例如:
1 2 3 4 5 6 | user> ((fn fact [x] (if (= x 0) 1 (* x (fact (dec x))))) 5) ;; ==> 120 |
是的,您可以使用
中均适用
1 2 | user> (loop [result 5 x 1] (if (= x 3) result (recur (* result 5) (inc x)))) 125 |
一种偶氮型Clojure解决方案如下所示:
1 2 | user> (reduce * (take 3 (repeat 5))) 125 |
或使用Math.pow();-)
1 2 | user> (java.lang.Math/pow 5 3) 125.0 |
循环可以是重复出现的目标,因此您也可以这样做。