Беда с этим макросом - PullRequest
       7

Беда с этим макросом

8 голосов
/ 29 июля 2010

Довольно смущающе, у меня возникли проблемы с правильной разработкой этого макроса.

Это макрос, как я его написал:

(defmacro construct-vertices
  [xs ys]
  (cons 'draw-line-strip
        (map #(list vertex %1 %2) xs ys)))

Он должен принимать две коллекции или последовательности, 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 / что-то, что должно быть оценено как (take 16 (iterate #(+ 0.1 %1) 0)) и (take 16 (cycle [0 -0.1 0 0.1])))).

Я понимаю, что это потому, чтоони передаются макросу без оценки, и поэтому я получаю, например, (vertex take take) в качестве моего первого результата (я верю).К сожалению, все, что я пытался сначала оценить, а затем выполнить переписывание макросов, провалилось / выглядело ужасно хакерским.

Я уверен, что здесь отсутствует какой-то базовый шаблон синтаксических кавычек / кавычек - я бы хотел получить помощь / указатели!

Большое спасибо.

РЕДАКТИРОВАТЬ Следует отметить, что draw-line-strip - это макрос, а vertex создает вершину OpenGL;они оба являются частью Penumbra Clojure + OpenGL библиотеки .

EDIT 2 Это для нужного мне графического инструмента, и основной мотивацией для его создания былобыть быстрее, чем JFreeCharts и компании.

РЕДАКТИРОВАТЬ 3 Полагаю, я должен заметить, что у меня do работает макро-версия, она просто ужасная и хакерская, как я упоминал выше.Он использует 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)

… при использовании этого с несколькимиДлинный список из тысячи предметов.Это потому, что я слишком много пишу в предварительно скомпилированный код, а файл классов не может обработать (я полагаю) такое количество данных / кода.Похоже, мне нужно каким-то образом получить версию функции draw-line-strip, как было предложено.

Я по-прежнему открыт для более элегантного, менее хакерского, макро решения этой проблемы.Если таковой существует!

Ответы [ 4 ]

4 голосов
/ 30 июля 2010

Я посмотрел на расширение макроса для draw-line-strip и заметил, что оно просто оборачивает тело в связывание, gl-begin и gl-end. Таким образом, вы можете поместить в него любой код, какой захотите.

Так

(defn construct-vertices [xs ys]
  (draw-line-strip
    (dorun (map #(vertex %1 %2) xs ys))))

должно работать.

2 голосов
/ 29 июля 2010

Если вам действительно нужно, чтобы 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

Обратите внимание, что это ужасный стиль, если только действительно не требуется.

2 голосов
/ 29 июля 2010

Почему бы не что-то подобное, используя функцию вместо макроса:

(defn construct-vertices [xs ys]
  (apply draw-line-strip (map #(list vertex %1 %2) xs ys)))

Это должно вызвать draw-line-strip с необходимыми аргументами.Этот пример не лучше всего подходит для макросов, которые не следует использовать там, где могут выполнять функции.

Примечание. Я не пробовал, поскольку у меня нет слизи в этом поле.*

РЕДАКТИРОВАТЬ: Снова глядя, я не знаю, если вы хотите оценить вершину перед вызовом draw-line-strip.В этом случае функция будет выглядеть так:

(defn construct-vertices [xs ys]
  (apply draw-line-strip (map #(vertex %1 %2) xs ys)))
1 голос
/ 29 июля 2010

Это похоже на типичную проблему с некоторыми макрос-системами в Лиспе. Обычная лиспская литература применима. Например На Лиспе Пола Грэма (использует 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 - это макрос. Лучше записать как функцию.

...