我想要一些东西,它给我传递给函数的实际值序列,类似于javascript函数中的arguments值。
我知道我可以使用
获取整个函数参数列表(defn fx [& args]
args)
<= (fx {:a 1} 2)
=> ({:a 1} 2)
但这消除了我的功能上的arity。我想要像
这样的东西(defn fx [{:keys [a]} b]
(MAGIC_FUNCTION_THAT_RETURNS_THE_ARGS_VALUES))
<= (fx {:a 1} 2)
=> ({:a 1} 2)
是否可以获取传递给函数的原始值序列?
答案 0 :(得分:4)
执行函数体时,参数已经被解构。您可以定义自己的defn
宏并公开这些值。我知道Lighttable在他们的Instarepl中执行此操作以显示参数值。
答案 1 :(得分:2)
我不知道如你所描述的那样做的方法,但根据你想要做的事情,有一些选择。
如果您想要确保仅使用两个参数调用该函数,请考虑前提条件:
(defn fx [& args]
{:pre [(= 2 (count args))]}
args)
user=> (fx 1 2)
(1 2)
user=> (fx 1 2 3)
AssertionError Assert failed: (= 2 (count args)) user/fx (NO_SOURCE_FILE:1)
如果您想要跟踪功能的预期,但仍然可以访问所有参数的矢量,则可以添加自己的元数据:
(defn
^{:my.ns/arglists '([{:keys [a]} b])}
fx [& args]
args)
user=> (fx 1 2)
(1 2)
user=> (-> #'fx meta :my.ns/arglists first)
[{:keys [a]} b]
如果您只想访问您描述的结构化值并访问args值,可以使用let:
(defn fx [{:keys [a]} b]
(let [args [{:a a} b]]
[a b args]))
user=> (fx {:a 1 :c 3} 2)
[1 2 [{:a 1} 2]]
user=> (fx {:a 1 :c 3} 2 4)
ArityException Wrong number of args (3) passed to: user$fx clojure.lang.AFn.throwArity (AFn.java:437)
您也可以将这些组合起来。
答案 2 :(得分:2)
使用参数销毁可以提供帮助。以下对我来说很好(据我所知,它也适用于旧版本的clojure)。
(defn example [ & [a b :as args]] [a b args])
(example 1 2)
=> [1 2 (1 2)]
关键是你可以在&
之后破坏论证。缺点是可以使用比预期更多的参数调用函数(例如(example 1 2 3)
是一个有效的调用。如果这可能是一个问题,应该特别小心。
注意:我在搜索类似功能时遇到了这个问题。我一直在挖掘并使用here和:as
中的一个想法,正如this回答中提到的那样,我找到了解决问题的方法。
答案 3 :(得分:1)
不太好,因为它需要将params作为向量传递,但似乎很适合
user.main=> (defn fx [[{:keys [a] :as e} b :as o]] [a b e o])
#'user.main/fx
user.main=> (fx [{:a 1} 2])
[1 2 {:a 1} [{:a 1} 2]]
user.main=>
答案 4 :(得分:0)
这是我能做的最好的。
(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选项(元数据,文档字符串,前置和后置,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)}
答案 5 :(得分:0)
在此示例中,您可以使用宏将参数绑定到符号_args
。
(defmacro defn-args [name args & body]
`(defn ~name ~args
(let [~'_args ~args]
~@body)))
然后,您可以在正文中使用_args来引用参数:
user> (defn-args foo [{:keys [a b]} y z] _args)
user> (foo {:a 1 :b 10} 2 3)
[{:a 1, :b 10} 2 3]