Macros 这个宏有问题吗
令人尴尬的是,我在正确设计这个宏时遇到了一些问题 这是我写的宏:Macros 这个宏有问题吗,macros,clojure,lisp,Macros,Clojure,Lisp,令人尴尬的是,我在正确设计这个宏时遇到了一些问题 这是我写的宏: (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
(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
=[01357]
和ys
=[131368]
如果我给我的宏普通'n'简单向量(例如,[1 2 3 4]
和[2 3 4 5]
),这很好,但如果我给它一个惰性seq/任何需要像那样计算的东西(取16(迭代(+0.1%1)0))
和(取16(循环[0-0.1 0.1])
)
我意识到这是因为这些被传递给未赋值的宏,因此我得到了,例如,(顶点take take)
作为我的第一个结果(我相信)。不幸的是,我试图先评估这些,然后执行宏重写的所有操作都失败了/看起来非常糟糕
我肯定我在这里缺少了一些基本的语法引号/取消引号模式——我想要一些帮助/指针
非常感谢
编辑我应该提到,
绘制线条条
是一个宏,顶点
创建一个OpenGL顶点;他们都是这个世界的一部分
编辑2这是我需要的一个自定义绘图工具,创建它的主要动机是比JFreeCharts和company更快
编辑3我想我应该注意到,我确实有一个宏版本在工作,就像我上面提到的那样,它非常可怕和粗糙。它使用eval
,如下所示,但如下所示:
(defmacro construct-vertices
[xs ys]
(cons 'draw-line-strip
(map #(list vertex %1 %2) (eval xs) (eval ys))))
不幸的是,我
错误:java.lang.ClassFormatError:在类文件tl/core$draw\u l$fn\u 9357(core.clj:14)的常量池中,该类索引3171无效。
…与数千项长列表一起使用时。这是因为我在预编译代码中写的太多了,而类文件无法处理(我想)那么多的数据/代码。看起来我需要,不知何故,获得一个功能版本的绘制线条条
,正如建议的那样
然而,对于这个问题,我仍然对一个更加优雅、不那么粗俗的宏观解决方案持开放态度。如果有的话 为什么不这样做,用函数代替宏:
(defn construct-vertices [xs ys]
(apply draw-line-strip (map #(list vertex %1 %2) xs ys)))
这将调用具有所需参数的绘制线带。这个例子不是最适合宏的,宏不应该用在函数可以做的地方
注意:我没有尝试,因为我没有在这个盒子上设置粘液
编辑:再次查看,我不知道在调用“绘制线带”之前是否要计算顶点。在这种情况下,函数将如下所示:
(defn construct-vertices [xs ys]
(apply draw-line-strip (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
请注意,除非确实有必要,否则这种样式很糟糕。这看起来像是Lisp中某些宏系统的典型问题。通常的Lisp文档适用。例如Paul Graham的(使用公共Lisp) 通常,宏使用它所包含的源并生成新的源。如果宏调用为(foo-bar),并且宏应根据bar的值生成不同的内容,则这通常是不可能的,因为bar的值通常不可用于编译器。BAR实际上在运行时只有一个值,而不是在编译器扩展宏时。因此,需要在运行时生成正确的代码——这可能是可能的,但通常被视为糟糕的风格 在这些宏系统中,不能应用宏。典型的解决方案如下所示(通用Lisp): 然而,使用上述解决方案并不总是可能的。例如,当参数的数量变化时
将DRAW-LINE-STRIP作为宏也不是一个好主意。最好将其编写为函数。我查看了draw line strip的宏展开,注意到它只是将主体包裹在绑定、gl begin和gl end中。所以你可以在里面放任何你想要的代码 所以
应该可以工作。为什么不写一个函数呢?因为据我所知,那是不可能的!我有这些
xs
和ys
数组,从某种意义上说,我需要在绘制线条
中重新格式化它们,并将它们包装在顶点
中。我也对宏很感兴趣,尽管我非常乐意看到一个使用函数的解决方案。实际上,不仅可以将其作为函数编写(请参阅Dev er Dev的回答),而且实际上不可能将其作为宏编写并使用任意seq参数(考虑编译代码时必须完全确定宏的扩展).draw lines strip
是一个宏,我应该提到。我不认为apply
与宏一起工作。不,它没有,你应该将它编辑到问题中,因为这会改变一切。还要提到什么是vertex
。还有一个问题:它真的需要是一个宏吗?它的名字明确地暗示了我们的工作一个函数…请注意,上述函数是一个函数,而不是宏,因此具有可用的运行时值xs
和ys
。然后使用这些值来构造一个绘制线带
表单,该表单在运行时进行宏扩展和编译。这当然会带来一定的性能成本,但这确实是唯一的方法除了重写绘制线条条
而不是宏(如果可能,这可能是最干净的解决方案)之外,继续回答问题要求.vertex不需要引用语法吗?编辑:啊,不,因为它在同一个ns中获取eval。我也会在这里发表评论:绘制线条带
是一个宏,因此应用
不能使用它。否则我会很高兴看到它
(apply (lambda (a b c)
(a-macro-with-three-args a b c))
list-of-three-elements)
(defn construct-vertices [xs ys]
(draw-line-strip
(dorun (map #(vertex %1 %2) xs ys))))