[英]a recursive Fibonacci function in Clojure
我是 clojure 的新手,他想看看有什么大惊小怪的。 确定感受它的最佳方法是编写一些简单的代码,我想我会从斐波那契函数开始。
我的第一个努力是:
(defn fib [x, n]
(if (< (count x) n)
(fib (conj x (+ (last x) (nth x (- (count x) 2)))) n)
x))
要使用它,我需要在调用函数时用 [0 1] 为 x 设置种子。 我的问题是,如果不将其包装在单独的函数中,是否可以编写一个只需要返回元素数量的函数?
做一些阅读让我找到了一些更好的方法来实现相同的功能:
(defn fib2 [n]
(loop [ x [0 1]]
(if (< (count x) n)
(recur (conj x (+ (last x) (nth x (- (count x) 2)))))
x)))
和
(defn fib3 [n]
(take n
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
无论如何,更多的是为了练习而不是其他任何事情,任何人都可以用更好的纯递归斐波那契函数版本来帮助我吗? 或者也许共享一个更好/不同的功能?
回答你的第一个问题:
(defn fib
([n]
(fib [0 1] n))
([x, n]
(if (< (count x) n)
(fib (conj x (+ (last x) (nth x (- (count x) 2)))) n)
x)))
这种类型的函数定义称为多元函数定义。 您可以在此处了解更多信息: http : //clojure.org/functional_programming
至于更好的 Fib 函数,我觉得你的 fib3 函数非常棒,展示了很多函数式编程概念。
这又快又酷:
(def fib (lazy-cat [0 1] (map + fib (rest fib))))
来自: http : //squirrel.pl/blog/2010/07/26/corecursion-in-clojure/
在 Clojure 中,实际上建议避免递归,而是使用loop
和recur
特殊形式。 这将看似递归的过程变成了迭代过程,从而避免堆栈溢出并提高性能。
以下是如何使用此技术实现斐波那契数列的示例:
(defn fib [n]
(loop [fib-nums [0 1]]
(if (>= (count fib-nums) n)
(subvec fib-nums 0 n)
(let [[n1 n2] (reverse fib-nums)]
(recur (conj fib-nums (+ n1 n2)))))))
loop
结构采用一系列绑定,提供初始值和一个或多个主体形式。 在任何这些主体形式中,对recur
的调用将导致使用提供的参数递归调用循环。
您可以使用 thrush 运算符稍微清理一下 #3(取决于您问的是谁;有些人喜欢这种风格,有些人讨厌它;我只是指出这是一种选择):
(defn fib [n]
(->> [0 1]
(iterate (fn [[a b]] [b (+ a b)]))
(map first)
(take n)))
也就是说,我可能会提取(take n)
并让fib
函数成为一个懒惰的无限序列。
(def fib
(->> [0 1]
(iterate (fn [[a b]] [b (+ a b)]))
(map first)))
;;usage
(take 10 fib)
;;output (0 1 1 2 3 5 8 13 21 34)
(nth fib 9)
;; output 34
一个好的递归定义是:
(def fib
(memoize
(fn [x]
(if (< x 2) 1
(+ (fib (dec (dec x))) (fib (dec x)))))))
这将返回一个特定的术语。 扩展它以返回前 n 项是微不足道的:
(take n (map fib (iterate inc 0)))
对于后来者。 接受的答案是一个稍微复杂的表达:
(defn fib
([n]
(fib [0 1] n))
([x, n]
(if (< (count x) n)
(recur (conj x (apply + (take-last 2 x))) n)
x)))
就其价值而言,这些年来,这是我对4Closure 问题 #26:斐波那契数列的解决方案
(fn [x]
(loop [i '(1 1)]
(if (= x (count i))
(reverse i)
(recur
(conj i (apply + (take 2 i)))))))
无论如何,我不认为这是最佳或最惯用的方法。 我在 4Clojure 上进行练习……并仔细研究Rosetta Code 中的代码示例的全部原因是学习clojure 。
顺便说一句,我很清楚斐波那契数列形式上包含 0 ......这个例子应该loop [i '(1 0)]
......但这不符合他们的规范。 尽管他们如何标记这个练习,也没有通过他们的单元测试。 它被编写为匿名递归函数,以符合 4Clojure 练习的要求……您必须在给定的表达式中“填空”。 (我发现匿名递归的整个概念有点令人费解;我知道(loop ... (recur ...
特殊形式被限制为尾递归......但它仍然很奇怪语法给我)。
我也会考虑@[Arthur Ulfeldt] 关于原始帖子中 fib3 的评论。 到目前为止,我只使用了一次 Clojure 的iterate
。
这是我为计算第 n 个斐波那契数而提出的最短递归函数:
(defn fib-nth [n] (if (< n 2)
n
(+ (fib-nth (- n 1)) (fib-nth (- n 2)))))
但是,除了 'n' 的前几个值之外,循环/递归的解决方案应该更快,因为 Clojure 对循环/递归进行了尾端优化。
这是我的方法
(defn fibonacci-seq [n]
(cond
(= n 0) 0
(= n 1) 1
:else (+ (fibonacci-seq (- n 1)) (fibonacci-seq (- n 2)))
)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.