来自命令式编程语言,我试图围绕Clojure,希望将其用于多线程功能。
来自4Clojure的问题之一是编写一个函数,该函数生成长度为N的Fibonacci数列表,对于N> 1。 1.我写了一个函数,但鉴于我的背景有限,我想知道这是否是最好的Clojure做事方式。代码如下:
(fn fib [x] (cond
(= x 2) '(1 1)
:else (reverse (conj (reverse (fib (dec x))) (+ (last (fib (dec x))) (-> (fib (dec x)) reverse rest first))))
))
答案 0 :(得分:7)
最惯用的“功能”方式可能是创建一个无限懒惰的斐波纳契数列,然后提取前n个值,即:
(take n some-infinite-fibonacci-sequence)
以下链接有一些非常有趣的方法可以沿着这些方向产生fibonnaci序列:
http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci
最后,这是另一个有趣的实现:
(defn fib [n]
(let [next-fib-pair (fn [[a b]] [b (+ a b)])
fib-pairs (iterate next-fib-pair [1 1])
all-fibs (map first fib-pairs)]
(take n all-fibs)))
(fib 6)
=> (1 1 2 3 5 8)
它并不尽可能简洁,但很好地展示了使用Clojure的解构,延迟序列和更高阶函数来解决问题。
答案 1 :(得分:5)
这是我非常喜欢的Fibonacci版本(我从clojure wikibook中获取了实现:http://en.wikibooks.org/wiki/Clojure_Programming)
(def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq)))
它的工作方式如下:想象一下,你已经拥有无限的斐波那契数列。如果您采用序列的尾部并将其按元素方式添加到原始序列中,则得到(斐波那契序列的尾部尾部)
0 1 1 2 3 5 8 ...
1 1 2 3 5 8 ...
-----------------
1 2 3 5 8 13 ...
因此您可以使用它来计算序列。您需要两个初始元素[0 1](或[1 1],具体取决于您启动序列的位置),然后您只需映射添加元素的两个序列。请注意,这里需要延迟序列。
我认为这是最优雅的(至少对我来说)思维延伸实现。
编辑:fib功能
(defn fib [n] (nth fib-seq n))
答案 2 :(得分:4)
这是一种做到这一点的方法,让你对懒惰序列有一点了解,虽然它当然不是计算斐波纳契数列的最佳方法。
鉴于Fibonacci序列的定义,我们可以看到它是通过重复将相同的规则应用于'(1 1)
的基本情况而构建的。 Clojure函数iterate
听起来对此有好处:
user> (doc iterate)
-------------------------
clojure.core/iterate
([f x])
Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
因此,对于我们的函数,我们需要一些东西,它采用我们到目前为止计算的值,将最近的两个值相加,并返回一个新值和所有旧值的列表。
(fn [[x y & _ :as all]] (cons (+ x y) all))
这里的参数列表只是意味着x
和y
将被绑定到作为函数参数传递的列表中的前两个值,包含前两个之后的所有参数的列表将被绑定到_
,作为参数传递给函数的原始列表可以通过all
引用。
现在,iterate
将返回一个无限的中间值序列,因此对于我们的情况,我们希望将它包装在只返回我们感兴趣的值的东西中;延迟评估将停止评估整个无限序列。
(defn fib [n]
(nth (iterate (fn [[x y & _ :as all]] (cons (+ x y) all)) '(1 1)) (- n 2)))
另请注意,这会以与实现相反的顺序返回结果;用reverse
来解决这个问题很简单。
编辑:或者实际上,正如amalloy所说,使用向量:
(defn fib [n]
(nth (iterate (fn [all]
(conj all (->> all (take-last 2) (apply +)))) [1 1])
(- n 2)))
答案 3 :(得分:4)
请参阅Stu Halloway撰写的 Programming Clojure 中的Christophe Grand的Fibonacci解决方案。这是我见过的最优雅的解决方案。
(defn fibo [] (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))
(take 10 (fibo))
另见