在Racket中c(a | d)+ r宏

Rac*_*oob 2 lisp macros cons racket

我想知道是否可以在Racket中编写一个可以转换每种形状的宏(c(a | d)+ r xs),其中c(a | d)+ r是匹配car,cdr,caar的正则表达式,干部,......等,先进入相应的组成和休息.

例如,这个宏应该采用(caadr'(1 2 3 4 5))并将其转换为(first(first(rest'(1 2 3 4 5)))).

沉(Mark Tarver的新编程语言)中有类似的东西:https://groups.google.com/group/qilang/browse_thread/thread/131eda1cf60d9094?hl = en

Eli*_*lay 14

很有可能在Racket中做到这一点,并且比上面做的更短.有两个(不是真的)技巧涉及:

  1. 使用Racket的#%top宏可以创建这样的绑定 - 超薄空气.这个宏被隐式地用于任何未绑定的变量引用("top",因为这些东西是对顶层变量的引用).

  2. 如果你让它们做到必要的最小值,那么宏就会变得简单得多,而将其余部分留给一个函数.

这是包含注释和测试的完整代码(实际代码很小,约10行).

#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
Run Code Online (Sandbox Code Playgroud)