You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Clojure递归斐波那契实现中conj行为的技术问询

解析Clojure中loop-recur实现斐波那契时conj的“异常”行为

你抓得特别准!这里的核心点其实是Clojure的conj函数行为完全取决于你传入的集合类型——你代码里初始的i是一个列表(list),而不是我们更常用的向量(vector),这才导致了看起来“反常规”的结果。

先明确一个关键规则:

  • 对于列表(list),conj会把元素添加到集合的头部(因为列表是链表结构,头部插入是O(1)的高效操作)
  • 对于向量(vector),conj才会把元素添加到集合的尾部(向量的尾部插入也是O(1)操作)

我们跟着fib(4)的执行流程走一遍,就能完全明白:

  1. 第一次进入loop:i是'(1 0)(这是一个列表),println输出(1 0)。此时(count i)是2,不等于4,所以执行recur。计算(apply + (take 2 i))得到1+0=1,然后conj把1加到列表头部,得到新的i为'(1 1 0)。
  2. 第二次loop:i是'(1 1 0),println输出(1 1 0)。(count i)是3,还是不等于4,继续recur。取前两个元素1和1求和得2,conj加到头部,新i变成'(2 1 1 0)。
  3. 第三次loop:i是'(2 1 1 0),println输出(2 1 1 0)。此时(count i)等于4了,所以执行(reverse i),把列表反转成(0 1 1 2),这就是最终返回值,也是你看到的最后一行输出。

顺便说下你标注的“逻辑存疑”:这段代码的逻辑是通过不断往列表头部追加前两项的和,凑够指定长度后反转,得到从0开始的斐波那契序列(比如fib(4)返回的就是前4个斐波那契数)。如果把初始的i改成向量[1 0],conj就会按你预期的往尾部加,代码逻辑会更直观:

(defn fib [x] 
  (loop [i [1 0]] 
    (println i) 
    (if (= x (count i)) 
      i 
      (recur (conj i (apply + (take 2 i)))))))

调用这个版本的fib(4),会输出[1 0] [1 0 1] [1 0 1 2],最终返回[1 0 1 2]。

内容的提问来源于stack exchange,提问作者Kannan Ramamoorthy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:25:45