我意识到宏俱乐部的第一条规则是不要使用宏,所以下面的问题更多的是作为学习Clojure的练习而不是其他任何东西(我意识到这不一定是宏的最佳用法).
我想编写一个简单的宏,它充当常规(defn)宏的包装器,并最终向定义的函数添加一些元数据.所以我想要这样的东西:
(defn-plus f [x] (inc x))
Run Code Online (Sandbox Code Playgroud)
......扩展到这样的东西:
(defn #^{:special-metadata :fixed-value} f [x] (inc x))
Run Code Online (Sandbox Code Playgroud)
原则上这对我来说似乎并不难,但是我无法[args]确定正确解析定义函数中的其他形式的具体细节.
作为奖励,如果可能的话,我希望宏能够处理所有不同形式的defn(即,有或没有docstrings,多个arity定义等).我在clojure-contrib/def包中看到了一些看起来可能有用的东西,但是很难找到使用它们的示例代码.
我想这样做(在REPL或任何地方)
(defn (symbol "print-string") [k] (println k))
Run Code Online (Sandbox Code Playgroud)
然后能够做到
(print-string "lol")
Run Code Online (Sandbox Code Playgroud)
或者,如果还有其他方法可以从宏中的自定义字符串创建defn,那么你可以把我推向正确的方向吗?
环境:Clojure 1.4
我试图从函数向量中动态提取函数元数据.
(defn #^{:tau-or-pi: :pi} funca "doc for func a" {:ans 42} [x] (* x x))
(defn #^{:tau-or-pi: :tau} funcb "doc for func b" {:ans 43} [x] (* x x x))
(def funcs [funca funcb])
Run Code Online (Sandbox Code Playgroud)
现在,检索REPL中的元数据(有点)是直截了当的:
user=>(:tau-or-pi (meta #'funca))
:pi
user=>(:ans (meta #'funca))
42
user=>(:tau-or-pi (meta #'funcb))
:tau
user=>(:ans (meta #'funcb))
43
Run Code Online (Sandbox Code Playgroud)
然而,当我尝试做一个地图,让:ans,:tau-or-pi或基本:name从元数据,我得到异常:
user=>(map #(meta #'%) funcs)
CompilerException java.lang.RuntimeException: Unable to resolve var: p1__1637# in this context, compiling:(NO_SOURCE_PATH:1)
Run Code Online (Sandbox Code Playgroud)
在做了一些搜索后,我从2009年的帖子中得到了以下想法(https://groups.google.com/forum/?fromgroups=#!topic/clojure/VyDM0YAzF4o):
user=>(map #(meta …Run Code Online (Sandbox Code Playgroud) 如何修改Clojure FN或宏的:arglist属性?
(defn tripler ^{:arglists ([b])} [a] (* 3 a))
(defn ^{:arglists ([b])} quadrupler [a] (* 4 a))
% (meta #'tripler) =>
{:arglists ([a]), :ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}
% (meta #'quadrupler) =>
{:arglists ([a]), :ns #<Namespace silly.testing>, :name quadrupler, :line 1, :file "NO_SOURCE_PATH"}
Run Code Online (Sandbox Code Playgroud)
好的,那里没有运气,所以我尝试执行以下操作。
(def tripler
(with-meta trippler
(assoc (meta #'tripler) :arglists '([c]))))
% (with-meta #'tripler) =>
{:ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}
Run Code Online (Sandbox Code Playgroud)
嗯,现在:arglists键不见了?好吧,我放弃了,我该怎么做?我只想修改:arglists的值。上面的示例使用defn,但我也想知道如何使用宏(defmacro)设置:arglists。
具体而言,在以下情况下会发生什么:
(defn avg
([] 0)
([& args] (/ (reduce + args) (count args))))
(avg)
Run Code Online (Sandbox Code Playgroud)
也就是说,我可以依靠clojure总是返回0而不是归零吗?
两者似乎都表示私有函数,类似于大多数 OOP 语言中的私有函数。是否存在功能差异或者只是语法糖?
我见过 defn ^:private 在环应用程序的处理程序上下文中使用。
任何人都可以解释为什么在下面的代码中,函数的名称在第一部分作为*(乘数)?
(defn bar
([a b] (bar a b 100))
([a b c] (* a b c)))
Run Code Online (Sandbox Code Playgroud)
给bar两个args (bar 2 3)产量(* 2 3 100)
(defn bar[{:keys [a b] :as args}] (prn "got" args))
Run Code Online (Sandbox Code Playgroud)
如果我们将上面的函数调用为
(bar {:a 1})
Run Code Online (Sandbox Code Playgroud)
它返回
{:a 1}
nil
Run Code Online (Sandbox Code Playgroud)
我希望有
{:a 1 :b nil}
Run Code Online (Sandbox Code Playgroud)