Я запутался в макро беспорядок.Выполнение макроса, вложенного в макросы с использованием переменных аргументов
Предпосылки: Идея состоит в том, что я определяю «ситуационный объект» (хэш-карту), который содержит логическое условие, некоторый текст и переменное число «параметров». У каждого варианта есть условие, некоторый текст и некоторые эффекты. Условия и эффекты превращаются в анонимные функции, текст просто сохраняется.
Так что я хочу определить макрос, который преобразует выражение в пару вложенных хэш-карт, включая некоторые сгенерированные лямбда-функции для оценки во время выполнения. Я скопировал некоторые идеи из 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 [email protected])))
(defmacro condify [body] `(fn [] ~body))
(defmacro make-fn [m]
`(fn [& args#]
(eval `(~'~m [email protected]#))))
; 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 [email protected])))
(defmacro option-in-list
[expr]
`(hash-map :cond (condify ~(first expr))
:text ~(second expr)
:effects (lambdify [email protected](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 [email protected])))
Я хочу начать с ситуация, так что если я определяю так:
(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"))
{Текст "option2",: эффекты #,: конд #}
(option-in-list ((= 1 2) "option2" (println "option 2 chosen")))
{Текст «option2 ",: effects #,: cond #}
Но когда я ева luate либо 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, и я даже не уверен, пойду ли я в совершенно неправильном направлении.
EDIT
мне удалось сделать что-то подобное, что работает, но я хотел бы знать, почему ..
Если я это сделать:
(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
)?
«ситуация» должна быть макросом, но то, что она называет, прямо или косвенно, должно быть лучше. – Thumbnail
Я не уверен, что я точно слежу за тем, что вы говорите, но я не думаю, что это так, так как вы можете иметь макросы, которые расширяются до других макросов и т. Д. (Например, в макроэксплуатации) – Sebastian
@ Thumbnail Нет, потому что «ситуация» фактически не вызывает какую-либо из этих функций; он распространяется на призыв к ним. Вы можете переписать все так, чтобы эти вспомогательные макросы были функциями, но нет необходимости. – amalloy