Macros c(a | d)和"x2B ;;拍中的r宏

Macros c(a | d)和"x2B ;;拍中的r宏,macros,lisp,racket,cons,Macros,Lisp,Racket,Cons,我想知道是否有可能在Racket中编写一个宏来转换所有形式的形状(c(a | d)+rxs),其中c(a | d)+r是一个正则表达式,匹配car、cdr、caar、cadr等等。。。等等,变成 第一个和第二个的相应组成 例如,这个宏应该取(caadr'(12345))并将其转换为(first(first(rest'(12345))) 在Shen(Mark Tarver的新编程语言)中类似这样的内容:您当然可以编写一些东西,将引用的s表达式引入,并将翻译输出为引用的s表达式 首先简单地将格式良好

我想知道是否有可能在Racket中编写一个宏来转换所有形式的形状(c(a | d)+rxs),其中c(a | d)+r是一个正则表达式,匹配car、cdr、caar、cadr等等。。。等等,变成 第一个和第二个的相应组成

例如,这个宏应该取(caadr'(12345))并将其转换为(first(first(rest'(12345)))


在Shen(Mark Tarver的新编程语言)中类似这样的内容:

您当然可以编写一些东西,将引用的s表达式引入,并将翻译输出为引用的s表达式

首先简单地将格式良好的列表(如
”(#\c#\a#\d#\r)
转换为第一个/其余的s表达式

现在使用symbol?、symbol->string、regexp match#rx“^c(a | d)+r$”、string->list和map构建解决方案

遍历输入。如果它是一个符号,请检查regexp(如果失败则按原样返回),转换为列表,并使用起始转换器。在嵌套表达式上递归

编辑:这里有一些写得不好的代码,可以将源代码翻译成源代码(假设目的是读取输出)


正如评论中提到的,我很好奇你为什么想要一个宏。如果目的是将源代码转换为可读的内容,您不想捕获输出以替换原始版本吗?

以下是我的实现(现在已固定为使用呼叫站点的
car
cdr
,因此您可以重新定义它们,它们将正常工作):

示例:

(biteme (car '(1 2 3 4 5 6 7)))        ; => 1
(biteme (cadr '(1 2 3 4 5 6 7)))       ; => 2
(biteme (cddddr '(1 2 3 4 5 6 7)))     ; => (5 6 7)
(biteme (caddddddr '(1 2 3 4 5 6 7)))  ; => 7
(let ((car cdr)
      (cdr car))
  (biteme (cdaaaaar '(1 2 3 4 5 6 7)))) ; => 6

是一本使用Common Lisp的书,但它有一个定义宏
,其中包含所有CXR
,可以实现您想要的功能。

在Racket中完全可以做到这一点,并且可以用比上面短得多的方式。有两个(并非真正的)技巧:

  • 使用Racket的宏可以凭空创建这样的绑定。该宏隐式地用于任何未绑定的变量引用(“top”,因为这些是对顶级变量的引用)

  • 如果您让宏执行必要的最小操作,并将其余的留给函数,宏将变得更简单

  • 下面是完整的代码,包括注释和测试(实际代码很小,大约10行)


    OP要求一个宏;如果它只是一个接受S表达式并返回它的函数,那么仍然需要一个eval来运行。:-)如果目的是翻译源代码以使其可读,则不需要宏。我认为OP想要一些东西将代码翻译成代码,而不是对其进行评估(尽管要求使用宏)。是的,这是一个合理的期望,但请参阅OP在我的帖子上的评论。@ChrisJester-Young:唉,你是对的。好吧,今天早上花点时间做这件事真是一件有趣的事情(这是我以前一直想做的事情)。@chris Ok,我试着让你的宏按照OP要求的方式工作。所以你可以让球拍很容易地表现出这种行为。但它突然使理解这种“易出错”语言中的代码和了解发生了什么变得更加困难。fallthrough宏最终会覆盖所有内容,这使得寄存器fallthrough宏程序员不友好。它很可爱,但我从来没有在生产代码中使用过它:它对人类太不友好了。谢谢Chris,但你能在操作员位置不使用biteme的情况下做到这一点吗?那么,你要求在应用程序位置出现无法识别的内容时激活一些宏,对吗?一种方法是覆盖Racket中的#%app。然而,应用于一种语言是如此普遍的变化!有关出于可疑目的而覆盖#%app的示例,请参见。同样地,将Chris Jester Young的解决方案挂接起来应该很简单。@RacketNoob是的,如果您更新宏(确保它是带有
    数据->语法的版本),并且记住在
    位中写入
    (我不喜欢忘记后者)。:-)@克里斯:在您的最后一个示例@RacketNoob:see中,我仍然收到“expand:unboundidentifier in module in:cdaaaaar”错误。唉,CL宏与Scheme宏有很大不同@Daimrod:Let Over Lambda中描述的解决方案不如本链接中描述的Shen中的解决方案优雅(因为它要求我们在需要使用任何cxr函数时与所有cxr表单一起使用):@RacketNoob:Wooa,我听说过Shen,但我从未想到它这么棒。这种宏看起来真的很神奇,我需要了解更多关于沈的信息,谢谢你的链接。:)但正如你在链接中所说的,我认为在Scheme或CL中,或者在CL中使用reader宏是不可能的。。。但那不像在沈那样干净。太好了!这个解决方案正是我想要的,谢谢!Racket是一种真正美丽而强大的语言。@RacketNoob大多数Racket开发者都推荐如何设计程序。这不是一本球拍手册,可能也不包括
    #%top
    ,但它仍然是一本很有用的书。@chris是的,它很有用。但是,不幸的是,HtDP是唯一一本关于球拍的书,而且只适合初学者。
    (define-syntax (biteme stx)
      (define (id->string id)
        (symbol->string (syntax->datum id)))
      (define (decomp id)
        (define match (regexp-match #rx"^c([ad])(.*)r$" (id->string id)))
        (define func (case (string-ref (cadr match) 0)
                      ((#\a) 'car)
                      ((#\d) 'cdr)))
        (datum->syntax id (list func (string->symbol (format "c~ar" (caddr match))))))
      (syntax-case stx ()
        ((_ (c*r x)) (regexp-match #rx"^c[ad]+r$" (id->string #'c*r))
         (with-syntax (((a d) (decomp #'c*r)))
           (syntax-case #'d (cr)
             (cr #'(a x))
             (_ #'(a (biteme (d x)))))))))
    
    (biteme (car '(1 2 3 4 5 6 7)))        ; => 1
    (biteme (cadr '(1 2 3 4 5 6 7)))       ; => 2
    (biteme (cddddr '(1 2 3 4 5 6 7)))     ; => (5 6 7)
    (biteme (caddddddr '(1 2 3 4 5 6 7)))  ; => 7
    (let ((car cdr)
          (cdr car))
      (biteme (cdaaaaar '(1 2 3 4 5 6 7)))) ; => 6
    
    #lang racket
    
    ;; we're going to define our own #%top, so make the real one available
    (require (only-in racket [#%top real-top]))
    ;; in case you want to use this thing as a library for other code
    (provide #%top)
    
    ;; non-trick#1: doing the real work in a function is almost trivial
    (define (c...r path)
      (apply compose (map (λ(x) (case x [(#\a) car] [(#\d) cdr])) path)))
    
    ;; non-trick#2: define our own #%top, which expands to the above in
    ;; case of a `c[ad]*r', or to the real `#%top' otherwise.
    (define-syntax (#%top stx)
      (syntax-case stx ()
        [(_ . id)
         (let ([m (regexp-match #rx"^c([ad]*)r$"
                                (symbol->string (syntax-e #'id)))])
           (if m
             #`(c...r '#,(string->list (cadr m)))
             #'(real-top . id)))]))
    
    ;; Tests, to see that it works:
    (caadadr '(1 (2 (3 4)) 5 6))
    (let ([f caadadr]) (f '(1 (2 (3 4)) 5 6))) ; works even as a value
    (cr 'bleh)
    (cadr '(1 2 3))    ; uses the actual `cadr' since it's bound,
    ;; (cadr '(1))     ; to see this, note this error message
    ;; (caddddr '(1))  ; versus the error in this case
    (let ([cr list]) (cr 'bleh)) ; lexical scope is still respected