所有的功能如何,我可以代替调用f与函数调用g使用的球拍宏?我是新手,我不知道如何处理语法对象,但我相信我想到的用例是一个球拍宏可以做的事情.请考虑以下示例,我想替换plus它mul.宏replace-plus-with-mul只返回current-seconds一个占位符,因为我不怎么样与语法的对象来代替做plus用mul.宏可以这样做吗?
#lang racket
(define-syntax replace-plus-with-mul
(lambda (stx) #'(current-seconds)))
(define plus (lambda (x y) (+ x y)))
(define mul (lambda (x y) (* x y)))
(define a 4)
(define b 2)
(define c (plus a b))
(replace-plus-with-mul d c) ;; (define d (mul a b))
(print d) ;; should print 8
Run Code Online (Sandbox Code Playgroud)
我没有看到一种简单的方法来精确地获得你想要的工作,但如果有额外的限制,这当然是可能的。
如果您同意宏调用在语法上必须包含的限制plus,那么只需在宏内部递归地替换plus所有mul内容
;; main.rkt
#lang racket
(define plus (lambda (x y) (+ x y)))
(define mul (lambda (x y) (* x y)))
(define-for-syntax (replace stx)
(syntax-case stx ()
[(a . b)
(datum->syntax stx (cons (replace #'a)
(replace #'b)))]
[_
(and (identifier? stx)
(free-identifier=? #'plus stx))
#'mul]
;; FIXME: need more cases (like box or vector), but
;; this is sufficient for the demo
[_ stx]))
(define-syntax (replace-plus-with-mul stx)
(syntax-case stx ()
[(_ id expr)
#`(define id
#,(replace (local-expand #'expr 'expression '())))]))
(replace-plus-with-mul c (plus 3 (let ([plus 10]) plus)))
c ; prints 30
(plus 3 (let ([plus 10]) plus)) ; prints 13
Run Code Online (Sandbox Code Playgroud)
如果您同意plus您想要更改的限制,则该限制不得已被使用,如以下代码:
(define (c) (plus 3 2))
(replace-plus-with-mul d (c))
Run Code Online (Sandbox Code Playgroud)
然后有几种方法可以实现这一点。一种是重写#%module-begin将全部替换plus为(if (current-should-use-mul?) mul plus)并扩展replace-plus-with-mul到(parameterize ([current-should-use-mul? #t]) ...). 这是完整的代码:
;; raquet.rkt
#lang racket
(provide (except-out (all-from-out racket)
#%module-begin)
(rename-out [@module-begin #%module-begin])
plus
mul
replace-plus-with-mul)
(define plus (lambda (x y) (+ x y)))
(define mul (lambda (x y) (* x y)))
(define current-should-use-mul? (make-parameter #f))
(define-for-syntax (replace stx)
(syntax-case stx ()
[(a . b)
(datum->syntax stx (cons (replace #'a)
(replace #'b)))]
[_
(and (identifier? stx)
(free-identifier=? #'plus stx))
#'(if (current-should-use-mul?) mul plus)]
;; FIXME: need more cases (like box or vector), but
;; this is sufficient for the demo
[_ stx]))
(define-syntax (@module-begin stx)
(syntax-case stx ()
[(_ form ...)
#'(#%module-begin (wrap-form form) ...)]))
(define-syntax (wrap-form stx)
(syntax-case stx ()
[(_ form) (replace (local-expand #'form 'top-level '()))]))
(define (activate f)
(parameterize ([current-should-use-mul? #t])
(f)))
(define-syntax (replace-plus-with-mul stx)
(syntax-case stx ()
[(_ id expr)
#`(define id (activate (lambda () expr)))]))
Run Code Online (Sandbox Code Playgroud)
和
;; main.rkt
#lang s-exp "raquet.rkt"
(define (c) (plus 3 (let ([plus 10]) plus)))
(replace-plus-with-mul a (c))
a ; prints 30
(c) ; prints 13
Run Code Online (Sandbox Code Playgroud)
从某种意义上说,你想做的事情需要一种惰性求值,这是一个巨大的语义变化。我不确定是否有一种好方法可以在不“损坏”其他代码的情况下做到这一点。