让内心深处

时间:2010-01-14 21:52:57

标签: lisp clojure

我正在使用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

3 个答案:

答案 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

  1. if-let的工作方式,如果if-let碰巧是(first xs)nil将是相同的),则解构绑定永远不会发生,所以Clojure不会抱怨无法将false绑定到nil

  2. 此外,[unpack v]接受一个else子句(其中你不能引用if-let绑定向量中绑定的变量 - 尽管如果你在else子句中,你知道他们在哪里if-letfalse

答案 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