代码之家  ›  专栏  ›  技术社区  ›  Isaac

这个宏有问题

  •  8
  • Isaac  · 技术社区  · 16 年前

    令人难堪的是,我在正确设计这个宏时遇到了一些困难。

    这是我写的宏:

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

    它需要接受两个集合或SEQ, 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] )但如果我给它一个懒惰的序列/任何需要评估的东西,比如 (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 library .

    编辑2 这是我需要的一个自定义绘图工具,创建它的主要动机是比JFreecharts和公司更快。

    编辑3 我想我应该注意到 做 有一个宏版本在工作,正如我上面提到的,它是可怕和黑客的。它使用 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)

    _当与几千个项目长列表一起使用时。这是因为我在预编译的代码中写了太多,而类文件无法处理(我想)那么多的数据/代码。看起来我需要,不知何故,获得一个函数版本 画线条 如前所述。

    不过,我仍然愿意为这个问题提供一个更优雅、不那么刻薄的宏观解决方案。如果存在的话!

    4 回复  |  直到 16 年前
        1
  •  4
  •   dreish    16 年前

    我查看了绘制线条条的宏扩展,注意到它只是用一个绑定、gl begin和gl end将主体包装起来。所以你可以把你想要的任何代码放在里面。

    所以

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

    应该工作。

        2
  •  2
  •   Marko    16 年前

    为什么不这样,用函数代替宏:

    (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)))
    
        3
  •  2
  •   Michał Marczyk    16 年前

    如果你真的需要 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
    

    请注意,这种样式很糟糕,除非它是 真正地 必要的。

        4
  •  1
  •   Rainer Joswig mmmmmm    16 年前

    这看起来像是Lisp中一些宏系统的典型问题。通常的Lisp文献适用。例如 On Lisp 作者:保罗·格雷厄姆(使用普通的口齿不清)。

    通常,宏使用它所包含的源并生成新的源。如果宏调用是(foo bar),并且宏应该根据bar的值生成不同的内容,那么这通常是不可能的,因为bar的值通常不可用于编译器。Bar实际上在运行时只有一个值,而不是编译器扩展宏时。因此,人们需要在运行时生成正确的代码——这可能是可能的,但通常被视为糟糕的风格。

    在这些宏系统中,宏不能应用。一个典型的解决方案如下(常见的lisp):

    (apply (lambda (a b c)
              (a-macro-with-three-args a b c))
           list-of-three-elements)
    

    不过,使用上述解决方案并不总是可能的。例如,当参数数目不同时。

    同样,把线条条作为一个宏也不是一个好主意。最好把它写成函数。

    推荐文章