我正在学习Clojure和功能编程,为了练习,我正在研究4clojure问题。
这个功能,(不是最好的方法......我知道)正在发挥作用。 (反向交错)但是,该功能重新调整为零。
(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)
问题是......为什么?
答案 0 :(得分:2)
重要的是要记住,Clojure并不像大多数命令式语言那样真正做语句。使用do
,可以评估副作用的多个表达式,然后返回最后一个的值,而let
和fn
等几个结构包含隐式do
。但是除了最后一个表达式之外的任何表达式都不可能停止评估并说“我们已经完成”,除非它抛出异常。就这样,整行
(if (nil? (first coll)) (do (println :ret ret) ret))
只能通过其副作用来看待。它将评估为ret
或nil
中的值,然后将被丢弃。
然后我们打开when-let
。因为它是when
的变体,如果条件满足,它将返回其正文的值,如果不满足则返回nil
。正文是recur
到循环开头的指令,因此该循环只能以值nil
终止。
自然修复似乎是采用if
形式的最后一个paren并在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))