Смущающе достаточно я испытываю некоторые затруднения при разработке этого макроса правильно.
Это - макрос, поскольку у меня есть он записанный:
(defmacro construct-vertices
[xs ys]
(cons 'draw-line-strip
(map #(list vertex %1 %2) xs ys)))
Это должно взять в двух наборах или seqs, xs
и ys
, и мне нужен он, чтобы дать мне …
(draw-line-strip (vertex 0 1) (vertex 1 1)
(vertex 3 3) (vertex 5 6)
(vertex 7 8))
… для xs
= [0 1 3 5 7]
и ys
= [1 1 3 6 8]
.
Это работает просто великолепно, если я даю свою макро-плоскость 'n' простые векторы (например. [1 2 3 4]
и [2 3 4 5]
) но не работает, если я даю ему lazy-seq/anything, который должен быть оценен как (take 16 (iterate #(+ 0.1 %1) 0))
и (take 16 (cycle [0 -0.1 0 0.1]))))
.
Я понимаю, что это вызвано тем, что они передаются макросу, неоцененному, и таким образом, я добираюсь, например, (vertex take take)
как мой первый результат (я действительно верю). К сожалению, все, я попытался сначала оценить их и затем выполнить мою макроперезапись, приводило к сбою/смотрело ужасно hacky.
Я уверен, что отсутствую, своего рода основной syntax-quote/unquote шаблон здесь-I'd любят некоторую справку/указатели!
Большое спасибо.
РЕДАКТИРОВАНИЕ я должен упомянуть, draw-line-strip
макрос, и vertex
создает вершину OpenGL; они - оба часть библиотеки Penumbra Clojure+OpenGL.
ОТРЕДАКТИРУЙТЕ 2, Это для пользовательского инструмента построения графика, в котором я нуждаюсь, и основная мотивация для создания, это должно было быть быстрее, чем JFreeCharts и компания.
ОТРЕДАКТИРУЙТЕ 3, я предполагаю, что должен отметить, что у меня действительно есть макро-работа версии, это просто неприятно и hacky, как я упомянул выше. Это использует eval
, как продемонстрировано ниже, но как это:
(defmacro construct-vertices
[xs ys]
(cons 'draw-line-strip
(map #(list vertex %1 %2) (eval xs) (eval ys))))
К сожалению, я получаю …
error: java.lang.ClassFormatError: Invalid this class index 3171 in constant pool in class file tl/core$draw_l$fn__9357 (core.clj:14)
… при использовании этого с длинным списком (списками) нескольких-тысяч-объекта. Это вызвано тем, что я пишу слишком много в предварительный скомпилированный код, и classfile не может обработать (я предполагаю), так много данных/кода. Похоже, что я должен, так или иначе, получить функциональную версию draw-line-strip
, как был предложен.
Я все еще открыт, однако, к более изящному, меньшему количеству hackish, макро-решению этой проблемы. Если Вы существуете!
Я посмотрел на расширение макроса для draw-line-strip и заметил, что оно просто обертывает тело в привязка, gl-begin и gl-end. Таким образом, вы можете поместить в него любой код, который хотите.
Итак,
(defn construct-vertices [xs ys]
(draw-line-strip
(dorun (map #(vertex %1 %2) xs ys))))
должно работать.
Если вам действительно нужен draw-line-strip
в качестве макроса и , вам нужен полностью общий метод выполнения того, что описывает текст вопроса и вы не особо заботьтесь о небольшом снижении производительности, вы можете использовать eval
:
(defn construct-vertices [xs ys]
(eval `(draw-line-strip ~@(map #(list 'vertex %1 %2) xs ys))))
; ^- not sure what vertex is
; and thus whether you need this quote
Обратите внимание, что это ужасный стиль, если он не действительно необходим.
Почему бы не сделать что-то вроде этого, используя функцию вместо макроса:
(defn construct-vertices [xs ys]
(apply draw-line-strip (map #(list vertex %1 %2) xs ys)))
Это должно вызвать draw-line-strip с требуемыми args. Этот пример не лучшим образом подходит для макросов, которые не следует использовать там, где это могут сделать функции.
Примечание: я не пробовал, так как у меня нет слима, установленного на этой коробке.
EDIT: Посмотрев еще раз, я не знаю, хотите ли вы оценить вершину перед вызовом draw-line-strip. В таком случае функция будет выглядеть так:
(defn construct-vertices [xs ys]
(apply draw-line-strip (map #(vertex %1 %2) xs ys)))
Это похоже на типичную проблему с некоторыми макросистемами в Lisp. Применяется обычная литература по Лиспу. Например, On Lisp Пола Грэма (использует Common Lisp).
Обычно макрос использует источник, который он заключает в себе, и генерирует новый источник. Если вызов макроса имеет вид (foo bar), и макрос должен генерировать что-то другое, основываясь на значении bar, то это обычно невозможно, поскольку значение bar обычно недоступно компилятору. BAR действительно имеет значение только во время выполнения, а не когда компилятор расширяет макросы. Таким образом, нужно генерировать правильный код во время выполнения - что возможно, но что обычно считается плохим стилем.
В таких макросистемах макросы не могут быть применены. Типичное решение выглядит следующим образом (Common Lisp):
(apply (lambda (a b c)
(a-macro-with-three-args a b c))
list-of-three-elements)
Однако не всегда возможно использовать вышеуказанное решение. Например, когда количество аргументов варьируется.
Также не очень хорошо, что DRAW-LINE-STRIP - это макрос. Его лучше записать как функцию.