我正在使用clojure,虽然我之前涉及过lisps,但我很难找到一种简洁的方法来在cond语句中嵌入let语句。例如,请考虑以下函数:
(defn operate-on-list [xs]
(let [[unpack vector] (first xs)]
(cond
[(empty? xs) 'empty
unpack vector
:else (operate-on-list (rest xs))])))
这是一个非常标准的列表递归操作,但它需要在列表中的第一个元素上做一些工作才能处理内容。当然,问题是列表可能是空的。
在此示例中,将unpack
更改为((first xs) 0)
和将vector
更改为((first xs) 1)
并不困难,但如果需要更多工作,这很快就会变得难看完成(第一个xs)。
有没有办法在cond中有效地使用let语句?
感谢。
-Nate
答案 0 :(得分:11)
在这种情况下,您最好使用if-let
:
(defn operate-on-list [xs]
(if-let [[unpack v] (first xs)]
(cond
unpack v
:else (operate-on-list (rest xs)))))
此代码遍历给定的列表 seq-able(list,vector,array ...)向量,并返回第一个向量的第二个元素,其第一个元素为true(意味着不是{{ 1}}或false
)。如果找不到这样的矢量,则返回nil
。
请注意nil
是一个内置函数,所以我选择了vector
作为变量名,以防万一将来需要在函数体中使用该函数。更重要的是,你在cond语法中使用了太多括号;已修复此版本。
更新:值得注意的另外两件事v
:
if-let
的工作方式,如果if-let
碰巧是(first xs)
(nil
将是相同的),则解构绑定永远不会发生,所以Clojure不会抱怨无法将false
绑定到nil
。
此外,[unpack v]
接受一个else子句(其中你不能引用if-let
绑定向量中绑定的变量 - 尽管如果你在else子句中,你知道他们在哪里if-let
或false
。
答案 1 :(得分:3)
;use conditional let: http://richhickey.github.com/clojure-contrib/cond-api.html
(use 'clojure.contrib.cond)
(cond-let [b]
nil b
12 (prn (+ b 1))
:else 17 )
;==> 13
另一个很好的例子可以在http://www.mail-archive.com/clojure@googlegroups.com/msg03684.html
找到答案 2 :(得分:2)
有点像这样,let
的范围内有cond
吗?
(defn operate-on-list [list]
(let [ el_first (first list) ]
(cond
(nil? el_first) (println "Finished")
:else (do
(let [ list_rest (rest list) ]
(println el_first)
(operate-on-list list_rest))))))
(operate-on-list '(1 2 3))
输出结果为:
1
2
3
Finished