Clojure 使用变量参数使宏嵌套在宏中是可行的
我陷入了一片混乱 背景:我的想法是定义一个“情境对象”(散列映射),它包含一个逻辑条件、一些文本和一个可变数量的“选项”。每个选项还有一个条件、一些文本和一些效果。将条件和效果转换为匿名函数,只保留文本 所以我想定义一个宏,将表达式转换成两个嵌套的hashmaps,包括一些生成的lambda函数,以便在运行时进行计算。我从中复制了一些制作Clojure 使用变量参数使宏嵌套在宏中是可行的,clojure,macros,Clojure,Macros,我陷入了一片混乱 背景:我的想法是定义一个“情境对象”(散列映射),它包含一个逻辑条件、一些文本和一个可变数量的“选项”。每个选项还有一个条件、一些文本和一些效果。将条件和效果转换为匿名函数,只保留文本 所以我想定义一个宏,将表达式转换成两个嵌套的hashmaps,包括一些生成的lambda函数,以便在运行时进行计算。我从中复制了一些制作makefn宏的想法,以便在其他宏中使用map,但这可能是错误的方法 守则: ; Two basic (silly maybe? let me know if
makefn
宏的想法,以便在其他宏中使用map,但这可能是错误的方法
守则:
; Two basic (silly maybe? let me know if I'm reinventing the wheel)
; macros for turning conditions and effects into functions.
(defmacro lambdify [& body] `(fn [] (do ~@body)))
(defmacro condify [body] `(fn [] ~body))
(defmacro make-fn [m]
`(fn [& args#]
(eval `(~'~m ~@args#))))
; option and option-in-list do the same but one takes a single parameter
; as a list. I'm trying out different things.
(defmacro option
[cnd text & effs]
`(hash-map :cond (condify ~cnd)
:text ~text
:effects (lambdify ~@effs)))
(defmacro option-in-list
[expr]
`(hash-map :cond (condify ~(first expr))
:text ~(second expr)
:effects (lambdify ~@(next (next expr)))))
(defmacro options
[& opts]
`(map (make-fn option-in-list) ~opts))
(defmacro situation
[conds title text & opt-list]
`(hash-map :cond (condify ~conds)
:title ~title
:text ~text :opts (options ~@opt-list)))
我想从情况开始,如果我定义这个:
(situation (< 1 5) "title" "desc"
((> 1 2) "option1" (println "option 1 chosen"))
((< 1 5) "option2" (println "option 2 chosen"))))
{:文本“选项2”,:效果#,:条件#}
{:文本“选项2”,:效果#,:条件#}
但当我评估选项
或情况
时,我得到:
(options ((< 1 5) "option1" (println "option 1 chosen"))
((= 1 2) "option2" (println "option 2 chosen")))
(选项((<15)“选项1”(选择println“选项1”))
((=12)“选项2”(选择打印项“选项2”))
java.lang.ClassCastException:java.lang.Boolean不能强制转换为clojure.lang.IFn
据我所知,这意味着它在某个地方试图计算一个列表,该列表的第一个成员是布尔值,因此它试图将其转换为函数,对吗
但我找不到发生的地方(或方式)
我对Clojure没有太多的经验,我甚至不确定自己是否走错了方向
编辑
我已经设法做了一些类似的工作,但我想知道为什么
如果我这样做:
(def sit
(situation (< 1 5) "title" "desc"
(option (> 10 2) "option1" (println "option 1 chosen"))
(option (< 1 5) "option2" (println "option 2 chosen"))))
(def-sit)
(情境(<15)“标题”“描述”
(选项(>10 2)“选项1”(选择println“选项1”))
(选项(<15)“选项2”(选择打印选项2))
(在情况声明中明确声明选项)然后它就工作了。因此,我(理解)从宏内部调用宏是有问题的。有没有一种方法可以使它不直接使用
选项
宏(即从情况
宏中调用它)?确定,最后成功地使它工作
(defmacro option
[expr]
`(hash-map :cond (condify ~(first expr))
:text ~(second expr)
:effects (lambdify ~@(next (next expr)))))
(defmacro options
[opts]
`(list ~@(map (make-fn option) opts)))
(defmacro situation
[conds title text & opt-list]
`(hash-map :cond (condify ~conds)
:title ~title
:text ~text
:opts (options ~opt-list)))
我有一个unquote和splice-unquote的混乱,在一个列表中传递内容,而不是作为一个内容列表,之后进行了评估,因此将bool转换为fn时出现了错误。好的,终于成功了
(defmacro option
[expr]
`(hash-map :cond (condify ~(first expr))
:text ~(second expr)
:effects (lambdify ~@(next (next expr)))))
(defmacro options
[opts]
`(list ~@(map (make-fn option) opts)))
(defmacro situation
[conds title text & opt-list]
`(hash-map :cond (condify ~conds)
:title ~title
:text ~text
:opts (options ~opt-list)))
我有一个unquote和splice-unquote的混乱,在一个列表中传递内容,而不是作为一个内容列表,这后来被评估,因此将bool转换为fn的错误。
情况
需要是一个宏,但它直接或间接调用的内容,最好是函数。我不确定我是否完全按照你说的,但我不认为是这样,因为你可以将宏扩展到其他宏,等等(就像在macroexpand中)@Thumbnail No,因为情况
实际上没有调用任何这些函数;它正在扩展到给他们打电话。你可以重写一些东西,使这些helper宏成为函数,但没有必要。但我不明白condify
和lambdify
如何成为函数,因为它们需要宏所做的事情:生成代码而不计算代码。有没有办法用函数来实现这一点,在处理宏时这些函数是否可用?情况
需要是一个宏,但它直接或间接调用的东西最好是函数。我不确定我是否完全按照你说的去做,但我认为情况并非如此,因为你可以将宏扩展到其他宏,等等(比如在macroexpand中)@Thumbnail No,因为sition
实际上并没有调用这些函数;它正在扩展到给他们打电话。你可以重写一些东西,使这些helper宏成为函数,但没有必要。但我不明白condify
和lambdify
如何成为函数,因为它们需要宏所做的事情:生成代码而不计算代码。有没有一种方法可以让函数实现这一点?这些函数在处理宏时是否可用?
(def sit
(situation (< 1 5) "title" "desc"
(option (> 10 2) "option1" (println "option 1 chosen"))
(option (< 1 5) "option2" (println "option 2 chosen"))))
(defmacro option
[expr]
`(hash-map :cond (condify ~(first expr))
:text ~(second expr)
:effects (lambdify ~@(next (next expr)))))
(defmacro options
[opts]
`(list ~@(map (make-fn option) opts)))
(defmacro situation
[conds title text & opt-list]
`(hash-map :cond (condify ~conds)
:title ~title
:text ~text
:opts (options ~opt-list)))