使用 as-binding 解构可变参数函数:不可能?

Dav*_*ood 4 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)
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试将其提取到函数中,则会出现异常:

(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)
Run Code Online (Sandbox Code Playgroud)

值得注意的是,这有效:

(defn foo [[x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))
Run Code Online (Sandbox Code Playgroud)

但是然后我必须将参数作为集合传递,即(foo [1 2 3]).

是否可以定义一个接受可变数量参数的函数,并将整组参数绑定到一个局部变量,而无需let在内部专门使用绑定?这让我觉得很奇怪,你不能只是这样做(defn foo [x & more :as full-list] ...是否有特殊的原因为什么这不起作用(或不应该)?

Dan*_*ero 5

如果您想要可变数量的 args,则缺少 &:

(defn foo [& [x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))
Run Code Online (Sandbox Code Playgroud)

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

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

(defn foo [ x y ] ...)
Run Code Online (Sandbox Code Playgroud)

可以像这样解构:

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

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

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