【问题标题】:How to make a Racket macro take an integer argument?如何使球拍宏采用整数参数?
【发布时间】:2012-11-12 04:35:46
【问题描述】:

我一直在尝试为“包装”函数创建一个宏,即,如果我有一个函数可以获取一个列表并将符号 'a 用于第一个元素,它通常被定义为 lambda (l ) (cons 'al ),但我想要一个宏,它将采用一个函数和一个整数表达式对列表,并通过创建一个新函数来“包装”该函数,该函数采用旧函数的一些参数并基于其余部分在对上,使用整数作为位置,使用表达式作为值来给出函数。像这样的:

(wrap list (0 'blah) (2 'bloo) (4 'blee))

应该扩展为:

(lambda (a1 a2 . rest)
  (apply list 'blah a1 'bloo a2 'blee rest))

问题是,我不知道如何让宏找到对中整数的值,它只知道它是一个语法对象。我对宏很陌生,这应该很简单,我只是在文档方面遇到了麻烦,除了关于宏的简单教程之外,我在网上找不到任何信息。任何帮助将不胜感激。

【问题讨论】:

    标签: syntax macros racket


    【解决方案1】:

    这似乎是一个疯狂的宏,尤其是当SRFI 26 使用起来更加直观时。而不是(wrap list (0 'blah) (2 'bloo) (4 'blee)),您可以使用:

    (cut list 'blah <> 'bloo <> 'blee <...>)
    

    这肯定更容易阅读。


    如果您真的必须编写这样的宏,这里有一种方法,将wrap 的用法转换为cut 的等效用法:

    (require (for-syntax syntax/parse) srfi/26)
    (define-syntax (wrap stx)
      (syntax-parse stx
        ((_ func:expr (idx:nat expr:expr) ...)
         (let* ((alist (map cons
                            (syntax->datum #'(idx ...))
                            (syntax-e #'(expr ...))))
                (upper (add1 (apply max -1 (map car alist))))
                (listfunc (lambda (i)
                            (cond ((assv i alist) => cdr)
                                  (else #'<>)))))
           (with-syntax (((args ...) (build-list upper listfunc)))
             #'(cut func args ... <...>))))))
    

    回答您的问题的关键是使用syntax-&gt;datum(用于深层语法剥离)或syntax-e(用于浅层语法剥离),即如何获取给定语法对象的整数。


    (附注:(致阅读本文的球拍专家。)我对syntax-parse 很陌生,所以我确信syntax-parse 专家可以找到更好的方法来编写上述内容。我最初将宏写为@987654333 @宏,然后拍打syntax-parse语法类。就是这样。)

    【讨论】:

    • 太棒了。我以前从未见过这个功能。谢谢一堆。而且我必须努力适应语法->数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2012-01-07
    相关资源
    最近更新 更多