これは私が調理できる最高のものです。
(def ^:dynamic *arguments* nil)
(defn unstructure [form]
(cond
(or (vector? form) (map? form)) (gensym)
(= form '&) '&
:else form))
(defmacro bind-args-defn [name args & body]
(let [simple-args (vec (map unstructure args))
i (.lastIndexOf simple-args '&)
[h r] (split-at (if (neg? i) (count simple-args) i) simple-args)
r (drop 1 r)]
`(defn ~name
~simple-args
(binding [*arguments* (lazy-cat ~@(map vector h) ~@r)]
(let [~args *arguments*]
~@body)))))
(bind-args-defn ;;my special val binding defn
silly ;;the name
[{:keys [a]} [b & c] & d] ;;the arg vector
{:vals *arguments* :a a :b b :c c :d d}) ;;the body
明らかに、これは defn に渡すことができる defn オプション (メタデータ、docstring、pre および post、arities など) の完全なセットを受け入れませんが、アイデアを示していると思います。
ベクトルをキャプチャし、元のベクトルと同じ長さのベクトルをargs
作成することで機能しますが、構造化は行われません。それを引数ベクトルとして使用します。次に、このベクトルを のないフラットなベクトルに変換し、これを に割り当てます。その後、元のベクトルを使用して分解されます。ちょっと複雑ですが、現時点で私が望むことはできます。simple-args
args
defn
simple-args
&
*arguments*
*arguments*
args
> (silly {:a 1} [2 3 4] 5 6)
{:vals ({:a 1} [2 3 4] 5 6), :a 1, :b 2, :c (3 4), :d (5 6)}