我正在使用clojure,并且虽然以前接触过lisps,但是在寻找一种干净的方法来将let语句嵌套在cond语句中时遇到了麻烦。例如,考虑以下功能:

(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语句吗?

谢谢。

-内特

最佳答案

在这种情况下,最好使用if-let:

(defn operate-on-list [xs]
  (if-let [[unpack v] (first xs)]
    (cond
      unpack v
      :else  (operate-on-list (rest xs)))))

此代码遍历给定的向量列表可序列化(列表,向量,数组...),并返回第一个向量的第二个元素,其第一个元素为true(表示falsenil不是)。如果找不到这样的向量,则返回nil

请注意,vector是内置函数,因此,我选择了v作为变量名,以防万一将来需要在体内使用该函数。更重要的是,您在cond语法中使用了太多括号;在此版本中已修复。

更新:关于if-let的另外两点值得注意:
  • if-let的工作方式,如果(first xs)恰好是nil(false相同),则不会发生破坏性绑定(bind),因此Clojure不会提示无法将nil绑定(bind)到[unpack v]
  • 同样,if-let接受else子句(在其中您不能引用if-let绑定(bind)向量中绑定(bind)的变量-尽管如果您在else子句中,您仍然知道它们在falsenil的位置)。
  • 关于lisp - 让内cond,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2067832/

    10-16 16:09