我迷上了一团糟。
背景:我的想法是我定义一个情境对象' (哈希映射),包含逻辑条件,某些文本和可变数量的'选项'。每个选项还有一个条件,一些文本和一些效果。条件和效果转化为匿名函数,文本只是保留。
所以我想定义一个宏,将表达式转换为几个嵌套的哈希映射,包括一些生成的lambda函数,用于在运行时进行评估。我已经复制了here中的一些想法,以使make-fn
宏在其他宏中使用地图,但也许这是错误的方式......
代码:
; 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"))))
我希望有一个像
这样的哈希映射 { :cond (.. the fn for (< 1 5)),
:title "title" ,
:text "desc",
:opts [{:cond ( the fn for (> 1 2))
:text "option1"
:effects: ( the fn for println... )}
{ .. the second option also as a hash}}
我知道option
和option-in-list
有效:
(option (= 1 2) "option2" (println "option 2 chosen"))
{:text&#34; option2&#34;,:effects#,:cond#}
(option-in-list ((= 1 2) "option2" (println "option 2 chosen")))
{:text&#34; option2&#34;,:effects#,:cond#}
但是当我评估options
或situation
时,我得到:
(options ((< 1 5) "option1" (println "option 1 chosen"))
((= 1 2) "option2" (println "option 2 chosen")))
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"))))
(在情境声明中明确声明选项)然后它可以工作。所以我(从中理解)从宏内部调用宏有些不对劲。有没有办法让它在没有直接使用option
宏的情况下工作(即从situation
宏中调用它)?
答案 0 :(得分:0)
好的,终于成功了。
(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)))
我有一个不引用和拼接 - 不引用的混乱,将事物放在列表中而不是作为事物列表,后来被评估,因此将bool转换为fn的错误。