代码之家  ›  专栏  ›  技术社区  ›  Jason Baker

如何编写一个方案宏,该宏定义一个变量并以字符串形式获取该变量的名称?

  •  1
  • Jason Baker  · 技术社区  · 14 年前

    这主要是对 this question . 我决定将雅格尼牢记在心,并创建了一个全局变量( libpython )我把它设置为 #f 最初,然后 set! 它什么时候 init 被称为。我添加了一个函数,用于检查该值是否已初始化:

      (define (get-cpyfunc name type)
        (lambda args
          (if libpython
            (apply (get-ffi-obj name libpython type) args)
            (error "Call init before using any Python C functions"))))
    

    现在我想做的就是。我想定义一个宏,它将采用以下方法:

    (define-cpyfunc Py_Initialize (_fun -> _void))
    

    并将其转换为:

    (define Py_Initialize (get-cpyfunc "Py_Initialize" (_fun -> _void)))
    

    我一直在阅读宏文档,试图弄明白这一点,但我似乎找不到一种方法来让它工作。有人能帮我做这个吗(或者至少给我一个宏的大致概念)?或者有没有一种不使用宏的方法?

    3 回复  |  直到 14 年前
        1
  •  1
  •   Eli Barzilay    14 年前

    我在另一个问题中回答了大部分问题(我没有看到这个)。使用像这样提取绑定的函数是很好的,但是这里的一个可能的问题是,因为您只在调用结果函数时生成绑定,所以每次调用都会重新创建这个绑定。快速解决这一问题的一个简单方法是使用承诺,比如:

    (require scheme/promise)
    (define (get-cpyfunc name type)
      (define the-function
        (delay (if libpython
                 (get-ffi-obj name libpython type)
                 (error "Call init before using any Python C functions"))))
      (lambda args (apply (force the-function) args)))
    

    但这基本上与我在上一个问题中发布的代码相同。

    更多随机笔记:

    • get-ffi-obj 将接受一个符号作为要绑定到的名称——这是有意的,以使此类宏(如上一个问题中的宏)变得容易。

    • 使用 (symbol->string 'name) 在宏中是可以的。正如我在上面对内森评论的评论回复中提到的,这意味着它在运行时被调用,但是mzscheme无论如何应该能够优化它,所以没有必要尝试编写一些复杂的宏来在编译时完成这项工作。

    • 查看plt目录——您会发现一个名为 ffi . 这是具有各种样式的绑定示例的集合。在这些示例中,创建绑定的宏非常常见。

        2
  •  1
  •   Nathan Shively-Sanders    14 年前

    为什么不把生成的代码改为

    (define Py_Initialize (get-cpyfunc 'Py_Initialize (_fun -> _void)))
    

    然后有 get-cpyfunc 运行 (symbol->string name) ?

    当然,有一种方法可以做到这一点 syntax-case (我不记得了 它的 当然,如果您使用的是cl-esque方案 define-macro .

        3
  •  0
  •   Jason Baker    14 年前

    这不是完整的答案,但我想出了一个同时满足这两个要求的宏(定义一个变量和一个具有该变量名称的字符串):

    > (define-syntax (my-syntax stx)
      (syntax-case stx ()
      [(_ id)
      #'(define-values (id) (values (symbol->string (quote id))))]))
    > (my-syntax y)
    > y
    "y"