使用宏替换一个函数调用

Mei*_*ang 5 racket

所有的功能如何,我可以代替调用f与函数调用g使用的球拍宏?我是新手,我不知道如何处理语法对象,但我相信我想到的用例是一个球拍宏可以做的事情.请考虑以下示例,我想替换plusmul.宏replace-plus-with-mul只返回current-seconds一个占位符,因为我不怎么样与语法的对象来代替做plusmul.宏可以这样做吗?

#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)

Sor*_*ase 5

我没有看到一种简单的方法来精确地获得你想要的工作,但如果有额外的限制,这当然是可能的。


如果您同意宏调用在语法上必须包含的限制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)

从某种意义上说,你想做的事情需要一种惰性求值,这是一个巨大的语义变化。我不确定是否有一种好方法可以在不“损​​坏”其他代码的情况下做到这一点。