清理Clojure功能

wes*_*erA 5 refactoring clojure fibonacci

来自命令式编程语言,我试图围绕Clojure,希望将其用于其多线程功能.4Clojure的
一个问题是编写一个函数,生成一个长度为N的Fibonacci数列表,对于N> 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))))
          ))
Run Code Online (Sandbox Code Playgroud)

mik*_*era 7

最惯用的"功能"方式可能是创建一个无限懒惰的斐波纳契数列,然后提取前n个值,即:

(take n some-infinite-fibonacci-sequence)
Run Code Online (Sandbox Code Playgroud)

以下链接有一些非常有趣的方法来产生这些线上的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)
Run Code Online (Sandbox Code Playgroud)

它并不尽可能简洁,但很好地展示了使用Clojure的解构,延迟序列和更高阶函数来解决问题.


Joe*_*ann 5

这是我非常喜欢的Fibonacci版本(我从clojure wikibook中获取了实现:http://en.wikibooks.org/wiki/Clojure_Programming)

 (def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq)))
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:想象一下,你已经拥有了无数的Fibonacci数.如果您采用序列的尾部并将其按元素方式添加到原始序列中,您将获得斐波纳契序列的(尾部尾部)

0 1 1 2 3 5 8 ...
1 1 2 3 5 8 ...
-----------------
1 2 3 5 8 13 ... 
Run Code Online (Sandbox Code Playgroud)

因此你可以用它来计算序列.您需要两个初始元素[0 1](或[1 1],具体取决于您启动序列的位置),然后您只需映射添加元素的两个序列.请注意,这里需要延迟序列.

我认为这是最优雅的(至少对我来说)思维延伸实现.

编辑:fib功能是

 (defn fib [n] (nth fib-seq n)) 
Run Code Online (Sandbox Code Playgroud)


Hug*_*ugh 4

这是一种可以让您接触到惰性序列的方法,尽管它肯定不是计算斐波那契序列的最佳方法。

给出斐波那契数列的定义,我们可以看到它是通过将相同的规则重复应用于 的基本情况而构建的'(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
Run Code Online (Sandbox Code Playgroud)

因此,对于我们的函数,我们需要一些东西来获取迄今为止计算的值,将两个最新值相加,并返回新值和所有旧值的列表。

(fn [[x y & _ :as all]] (cons (+ x y) all))
Run Code Online (Sandbox Code Playgroud)

这里的参数列表仅意味着 和xy绑定到作为函数参数传递的列表中的前两个值,包含前两个值之后的所有参数的列表将绑定到_,并将原始列表作为参数传递给函数可以通过 参考all

现在,iterate将返回中间值的无限序列,因此对于我们的情况,我们希望将其包装在仅返回我们感兴趣的值的东西中;惰性求值将停止整个无限序列的求值。

(defn fib [n]
   (nth (iterate (fn [[x y & _ :as all]] (cons (+ x y) all)) '(1 1)) (- n 2)))
Run Code Online (Sandbox Code Playgroud)

另请注意,这会以与您的实现相反的顺序返回结果;reverse当然,解决这个问题很简单。

编辑:或者实际上,正如 amalloy 所说,通过使用向量:

(defn fib [n]
   (nth (iterate (fn [all]
                   (conj all (->> all (take-last 2) (apply +)))) [1 1])
        (- n 2)))
Run Code Online (Sandbox Code Playgroud)