我编写了一个专门的函数构造,它实际上只是一个Clojure函数。所以基本上我有一个函数(类似于fn
)和一个调用我的专用函数的函数(类似于CL' s funcall
)。
我的构造函数分配元数据(在编译时),因此我可以区分" my"函数和其他/普通的Clojure函数。
我想要做的是创建一个允许用户编写代码的宏,就像我的函数是正常函数一样。它会通过遍历代码来实现,而在函数调用中,当被调用者是一个专门的函数时,它会改变调用,因此它会使用我的调用者(并且还会注入一些额外的信息)。例如:
(defmacro my-fn [args-vector & body] ...)
(defmacro my-funcall [myfn & args] ...)
(defmacro with-my-fns [& body] ...)
(with-my-fns
123
(first [1 2 3])
((my-fn [x y] (+ x y))) 10 20)
; should yield:
(do
123
(first [1 2 3])
(my-funcall (my-fn [x y] (+ x y)) 10 20))
我在词汇环境中遇到了问题。例如:
(with-my-fns
(let [myf (my-fn [x y] (+ x y))]
(myf))
在这种情况下,当我想写的宏(即with-my-fns
)遇到(myf)
时,它会将myf
视为符号,而我无法访问元数据。它也不是Var,所以我不能resolve
它。
我很想知道,因为否则我必须在运行时对几乎所有单个函数调用进行检查。请注意,如果我的值的元数据是实际的Clojure元数据,我真的不在乎;如果它可以与类型系统一起使用,那么它和它一样好。
P.S。我最初只是想问一下词汇环境,但也许我应该知道哪些方法会失败? (或者甚至上面的内容实际上是一个XY问题?我欢迎建议)。
答案 0 :(得分:1)
正如@OlegTheCat已在评论部分指出,使用元数据的想法不起作用。
但是我可能有一个你可以忍受的解决方案:
(ns cl-myfn.core)
(defprotocol MyCallable
(call [this magic args]))
(extend-protocol MyCallable
;; a clojure function implements IFn
;; we use this knowledge to simply call it
;; and ignore the magic
clojure.lang.IFn
(call [this _magic args]
(apply this args)))
(deftype MyFun [myFun]
MyCallable
;; this is our magic type
;; for now it only adds the magic as first argument
;; you may add all the checks here
(call [this magic args]
(apply (.myFun this) magic args)))
;;turn this into a macro if you want more syntactic sugar
(defn make-myfun [fun]
(MyFun. fun))
(defmacro with-myfuns [magic & funs]
`(do ~@(map (fn [f#]
;; if f# is a sequence it is treated as a function call
(if (seq? f#)
(let [[fun# & args#] f#]
`(call ~fun# ~magic [~@args#]))
;; if f# is nonsequential it is left alone
f#))
funs)))
(let [my-prn (make-myfun prn)]
(with-myfuns :a-kind-of-magic
123
[1 2 3]
(prn :hello)
(my-prn 123)))
;; for your convenience: the macro-expansion
(let [my-prn (make-myfun prn)]
(prn (macroexpand-1 '(with-myfuns :a-kind-of-magic
123
[1 2 3]
(prn :hello)
(my-prn 123)))))
输出:
:hello
:a-kind-of-magic 123
(do 123 [1 2 3] (cl-myfn.core/call prn :a-kind-of-magic [:hello]) (cl-myfn.core/call my-prn :a-kind-of-magic [123]))