4

これまで、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] ...機能しない (または機能しない) 特定の理由はありますか?

4

1 に答える 1

5

可変数の引数が必要な場合は、 & がありません:

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

Clojure の param 定義&には、引数の可変数を示す char という特殊なケースが 1 つだけあります。残りは単純な名前付き引数です。

これで、マップまたはリスト構文を使用して各単純引数を分解できます。例えば:

(defn foo [ x y ] ...)

次のように分解できます。

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

したがって、最初のパラメーターは少なくとも 2 つの要素のリストであり、2 番目のパラメーターはいくつかのキーを持つマップであると予想されます。これは依然として 2 つのパラメーターの fn であり、Clojure は x が実際に少なくとも 2 つの要素を持つことを強制しないことに注意してください。x が空のリストの場合、x1 と x2 は nil になります。

あなたの質問に戻って、私の答えを見ると、私のfnには可変数の引数を持つ必須パラメータが0つあるのに対し、あなたが持っているものには可変数の引数を持つ1つの必須パラメータがあることがわかります。私がやっていることは、var arg を破壊することです。

于 2014-10-12T22:30:32.390 に答える