为什么这个函数返回 nil?

Why this function is returning nil?

我正在学习Clojure和函数式编程,为了练习,我正在研究4clojure的问题。

此功能(不是最好的方法.. 我知道)正在运行。 (反向交错)但是,该函数正在重新调整 nil。

(defn reverse_interleave
  [coll ss]
  (let [xx (dec ss)]
    (loop [coll (reverse coll) s xx _ss ss ret `()]
      (if (nil? (first coll)) (do (println :ret ret) ret))
      (when-let [x (first coll)]
                        (recur 
                          (rest coll)
                          (if (zero? s) xx (dec s))
                          (if (or (= 1 _ss) (zero? _ss)) 0 (dec _ss))
                          (if (zero? _ss)
                            (map-indexed #(if (= % s) (cons x %2) %2) ret)
                            (cons (list x) ret))
                            ))
      )) ret)


(reverse_interleave (range 9) 3)

问题是……为什么?

请务必记住,Clojure 并不像大多数命令式语言那样真正执行 语句。使用 do 可以评估多个表达式的副作用,然后 return 最后一个的值,并且 letfn 等几个结构包含隐式 do。但是除了最后一个表达式之外的任何表达式都不可能停止计算并说 "we're done" 除非它抛出异常。因此,整行

(if (nil? (first coll)) (do (println :ret ret) ret))

只能从它的副作用来看。它将评估为 retnil 中的值,然后将被丢弃。

然后我们开一个when-let。因为它是 when 的变体,如果满足条件,它将 return 其主体的值,否则将 nil 。正文是一条recur到循环开始的指令,所以这个循环只能在值nil.
处终止 自然的解决方法似乎是采用 if 形式的最后一个括号并将其移动到 when-let 之后,这样整个形式就是 else-case 的值。您的代码也无法为我编译,因为它在创建它的循环之外使用了名称 ret,但是随着它的消失,它似乎可以按预期工作:

(defn reverse_interleave
  [coll ss]
  (let [xx (dec ss)]
    (loop [coll (reverse coll) s xx _ss ss ret `()]
      (if (nil? (first coll)) 
        (do (println :ret ret) ret)
        (when-let [x (first coll)]
          (recur 
           (rest coll)
           (if (zero? s) xx (dec s))
           (if (or (= 1 _ss) (zero? _ss)) 0 (dec _ss))
           (if (zero? _ss)
             (map-indexed #(if (= % s) (cons x %2) %2) ret)
             (cons (list x) ret))))))))

(reverse_interleave (range 9) 3)
;;returns ((0 3 6) (1 4 7) (2 5 8))