Recursion Clojure中的递归Fibonacci函数

Recursion Clojure中的递归Fibonacci函数,recursion,clojure,fibonacci,tail-recursion,Recursion,Clojure,Fibonacci,Tail Recursion,我是clojure的新来者,我想看看到底是怎么回事。我想最好的办法就是写一些简单的代码,我想我应该从斐波那契函数开始 我的第一个努力是: (defn fib [x, n] (if (< (count x) n) (fib (conj x (+ (last x) (nth x (- (count x) 2)))) n) x)) 不管怎样,为了练习的目的,有人能帮我找到一个更好的纯递归斐波那契函数吗?或者共享更好/不同的功能?回答第一个问题: (defn fib (

我是clojure的新来者,我想看看到底是怎么回事。我想最好的办法就是写一些简单的代码,我想我应该从斐波那契函数开始

我的第一个努力是:

(defn fib [x, n]
  (if (< (count x) n) 
    (fib (conj x (+ (last x) (nth x (- (count x) 2)))) n)
    x))

不管怎样,为了练习的目的,有人能帮我找到一个更好的纯递归斐波那契函数吗?或者共享更好/不同的功能?

回答第一个问题:

(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)))
(定义fib
([n]
(fib[01]n)
([x,n]
(如果(<(计数x)n)
(fib(连体x(+(最后一个x)(第n个x(-(计数x)2)))n)
x) ))
这种类型的函数定义称为多元函数定义。您可以在此处了解更多信息:

至于更好的Fib函数,我认为您的fib3函数非常棒,展示了许多函数编程概念。

这既快又酷:

(def fib (lazy-cat [0 1] (map + fib (rest fib))))
发件人:
一个好的递归定义是:

(def fib 
  (memoize 
   (fn [x]
       (if (< x 2) 1
       (+ (fib (dec (dec x))) (fib (dec x)))))))

你可以使用画眉操作符来清理#3(取决于你问谁;有些人喜欢这种风格,有些人讨厌它;我只是指出这是一种选择):

也就是说,我可能会提取
(取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

在Clojure中,实际上建议避免递归,而是使用
循环
递归
特殊形式。这将看起来像一个递归过程转变为一个迭代过程,避免堆栈溢出并提高性能

下面是一个使用此技术实现斐波那契序列的示例:

(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)))))))

循环
构造采用一系列绑定,这些绑定提供初始值和一个或多个主体形式。在任何这些主体形式中,调用
recur
都会导致使用提供的参数递归调用循环。

对于后来者。公认的答案是一个稍微复杂的表达:

(定义fib
([n]
(fib[01]n)
([x,n]
(如果(<(计数x)n)
(重复(联合x(应用+(取最后2 x)))n)
x) ))

鉴于这些年来的价值,以下是我的解决方案

无论如何,我不认为这是最佳或最惯用的方法。我在4Clojure做练习的全部原因。。。仔细研究代码示例是为了学习

顺便说一句,我很清楚斐波那契序列形式上包括0。。。这个例子应该
循环[i'(10)]
。。。但这不符合他们的规范,也不能通过他们的单元测试,不管他们如何标记这个练习。它是作为匿名递归函数编写的,以符合4Clojure练习的要求。。。你必须在一个给定的表达式中“填空”。(我发现匿名递归的整个概念有点令人费解;我知道
(循环…(recur…
特殊形式被限制为…,但对我来说它仍然是一种奇怪的语法)


我还将考虑[Arthur Ulfeldt]关于原始帖子中fib3的评论。到目前为止,我只使用了Clojure的
迭代
一次。

以下是我提出的计算第n个Fibonacci数的最短递归函数:

(defn fib-nth [n] (if (< n 2)
                n
                (+ (fib-nth (- n 1)) (fib-nth (- n 2)))))
(定义光纤[n](如果(
但是,除了“n”的前几个值之外,使用循环/递归的解决方案应该更快,因为Clojure对循环/递归进行尾部优化。

这是我的方法

(defn fibonacci-seq [n]
  (cond
    (= n 0) 0
    (= n 1) 1
    :else (+ (fibonacci-seq (- n 1)) (fibonacci-seq (- n 2)))
    )
  )

如果我理解正确的话,它看起来像是重载函数的一个别致的名称。非常好用,谢谢。“Multi-arity”比“重载”更具体。“Multi-arity”表示“通过参数的数量区分”,而“重载”通常表示“通过参数的数量或类型区分”所以多重算术是重载方法的一个子集。我们如何编写一个没有递归的不可变版本呢?fib3是这些方法中最难懂的,很难理解,但非常有趣。(def fib(lazy cat[01](map+fib(rest fib)))和(取5个fib)将返回前5个术语。同样,我正在努力将其作为一个函数来编写:(defn fib([n](take n fib))([](lazy cat[01](map+fib(rest fib‘‘‘‘‘‘‘‘‘))不起作用。如果理解这5行代码的困难(我在谈论树算法)不会给你带来任何关于这种语言的危险信号……另外,你能数一数代码中的分配数吗?它非常高。仅仅因为运行时线性扩展并不意味着它很快。@richc它最初定义为一个变量,但你将它改为一个函数。所以你必须将
fib
的所有用法改为
(fib)
在您的实现中。FWIW:(fn[n](先取n(映射)(迭代(fn[[ab]]][b(+ab)])'(11()())(1))())()()))。
(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
(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)))))))
(fn [x] 
    (loop [i '(1 1)]
        (if (= x (count i))
            (reverse i)
            (recur 
              (conj i (apply + (take 2 i)))))))
(defn fib-nth [n] (if (< n 2)
                n
                (+ (fib-nth (- n 1)) (fib-nth (- n 2)))))
(defn fibonacci-seq [n]
  (cond
    (= n 0) 0
    (= n 1) 1
    :else (+ (fibonacci-seq (- n 1)) (fibonacci-seq (- n 2)))
    )
  )