让内心深处

So8*_*res 5 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))])))
Run Code Online (Sandbox Code Playgroud)

它是列表上非常标准的递归操作,但它需要在列表中的第一个元素上进行一些工作才能使用内容.当然,问题是列表可能是空的.

在这个例子中,改变unpackto ((first xs) 0)and vectorto 并不难((first xs) 1),但是如果需要做更多的工作(第一个xs),这很快就会变得很难看.

有没有办法在cond中有效地使用let语句?

谢谢.

-Nate

Mic*_*zyk 11

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

(defn operate-on-list [xs]
  (if-let [[unpack v] (first xs)]
    (cond
      unpack v
      :else  (operate-on-list (rest xs)))))
Run Code Online (Sandbox Code Playgroud)

此代码遍历给定列表 seq-able(list,vector,array ...)的向量,并返回第一个向量的第二个元素,其第一个元素为true(表示不是falsenil).nil如果没有找到这样的向量,则返回.

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

更新:另外两件值得注意的事情if-let:

  1. 该方法if-let的工作原理,如果(first xs)恰好是nil(false将是相同的),解构绑定从来没有发生,所以Clojure中不会抱怨不能够绑定nil[unpack v].

  2. 另外,if-let接受一个else子句(其中你不能引用if-let绑定向量中绑定的变量- 尽管如果你在else子句中,你知道它们在哪里false或者nil无论如何).

  • 另请参阅`when-let`,当您只有一个分支时,这更加惯用. (2认同)