使用as-binding来解析可变函数:不可能吗?

时间:2014-10-12 20:18:48

标签: clojure destructuring

到目前为止,我一直认为你可以在let绑定中做任何事情,你可以在defn形式的参数向量中做。

然而,我只是注意到了这一点 - 如果我使用let绑定执行此操作,则可行:

(let [[x & more :as full-list] (range 10)]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

; x: 0 
; more: (1 2 3 4 5 6 7 8 9) 
; full list: (0 1 2 3 4 5 6 7 8 9)

但如果我尝试将其拉入函数中,我会得到一个例外:

(defn foo [x & more :as full-list]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

; CompilerException java.lang.RuntimeException: Unexpected parameter, compiling:(/tmp/form-init615613631940782255.clj:1:1)

值得注意的是,这有效:

(defn foo [[x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

但是我必须将论证作为集合传递,即(foo [1 2 3])

是否可以定义一个带有可变数量参数的函数,并将整个参数组绑定到局部变量,而无需在内部使用let绑定?让我感到奇怪的是,你不能做到(defn foo [x & more :as full-list] ...是否有一个特殊的原因导致它不能(或不应该)起作用?

1 个答案:

答案 0 :(得分:4)

如果你想要一个可变数量的args,你就错过了&:

(defn foo [& [x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

Clojure param定义只有一个特殊情况,即& char,表示可变数量的参数。其余的都是简单的命名参数。

现在可以使用map或list语法对每个简单参数进行解构。例如:

(defn foo [ x y ] ...)

可以像以下一样进行解构:

(defn foo [[x1 x2 & x-more :as x] {:keys [y1 y2 y3]}] ...)

所以我们说我们期望第一个参数是至少2个元素的列表,第二个参数是带有一些键的映射。请注意,这仍然是两个参数的fn,并且Clojure不会强制执行x实际上至少有两个元素。如果x是空列表,则x1和x2将为nil。

回到你的问题,如果你看看我的答案,你会看到我的fn有0个强制参数,参数数量可变,而你拥有的参数有1个强制参数和一个可变数量的参数。我正在做的只是解构var arg。