问题描述
我想知道是否有可能在Racket中编写一个宏来转换每种形状的形状(c(a | d)+ r xs),其中c(a | d)+ r是与car,cdr匹配的正则表达式,caar,cadr等相应的第一"和休息"的组成.
I wonder if it's possible to write a macro in Racket that would translate every form of shape (c(a|d)+r xs), where c(a|d)+r is a regular expression matching car, cdr, caar, cadr, ... etc, intothe corresponding composition of first and rest.
例如,此宏应采用(caadr'(1 2 3 4 5))并将其转换为(first(first(rest'(1 2 3 4 5)))).
For example, this macro should take (caadr '(1 2 3 4 5)) and transform that to (first (first (rest '(1 2 3 4 5)))).
沉(Mark Tarver的新编程语言)中的代码如下: https://groups.google.com/group/qilang/browse_thread/thread/131eda1cf60d9094?hl=zh_CN
Something like this in Shen (Mark Tarver's new programming language): https://groups.google.com/group/qilang/browse_thread/thread/131eda1cf60d9094?hl=en
推荐答案
完全有可能在Racket中做到这一点,并且比上述方法要短得多.涉及两个技巧(不是真的):
It is very possible to do exactly that in Racket, and in a much shorter way than done above. There are two (not-really) tricks involved:
-
使用Racket的宏使创建此类绑定成为可能.在所有未绑定的变量引用("top",因为这些东西都是对顶级变量的引用)中隐式使用此宏.
Using Racket's
#%top
macro makes it possible to create such bindings-out-of-thin-air. This macro is getting used implicitly around any variable reference that is unbound ("top" because these things are references to toplevel variables).
如果使宏执行必要的最小操作,并将其余部分留给函数,宏就会变得简单得多.
Macros become much simpler if you make them do the necessary minimum, and leave the rest to a function.
这是带有注释和测试的完整代码(实际代码很小,大约10行).
Here's the complete code with comments and tests (the actual code is tiny, ~10 lines).
#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
这篇关于球拍中的c(a | d)+ r宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!