Clojure 为什么这个函数返回nil?
我正在学习Clojure和函数式编程,为了练习,我正在研究4clojure问题 这个函数(我知道不是最好的方法)正在工作。 (反向交织)但是,函数正在重新调整nilClojure 为什么这个函数返回nil?,clojure,Clojure,我正在学习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)
(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
可以计算多个表达式的副作用,然后返回最后一个表达式的值,并且像let
和fn
这样的几个结构包含隐式do
。但除了最后一个表达式之外,任何表达式都不可能停止求值并说“我们完成了”,除非它抛出异常。因此,整个生产线
(if (nil? (first coll)) (do (println :ret ret) ret))
只能从它的副作用中看出。它将作为ret
中的值或nil
中的值进行计算,然后将其丢弃
然后我们在let时打开一个。因为它是when
的变体,如果满足条件,它将返回其主体的值,如果不满足条件,它将返回nil
。正文是一条指令,用于循环
到循环的开头,因此此循环只能在值nil
中终止
自然的解决方法似乎是将if
表单的最后一个paren移到when let
之后,这样整个表单就是else案例的值。您的代码本身也无法为我编译,因为它在创建它的循环之外使用了名称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))
您在循环中定义了一个变量ret
,但它不存在于循环之外。函数中的最后一个ret
在循环之外,因此它不是同一个变量。当你评估你的代码时,你甚至会得到一个编译器的例外。klebervirgilio,你能稍微改进一下你的问题标题吗?仅仅是标题?