Lil*_*ung 8 macros inheritance scheme r5rs
受关于函数而不是宏的相关问题的评论主题的启发.
有没有办法扩展Scheme语法定义,以便它可以使用新定义中语法的先前定义?此外,这必须是可扩展的,也就是说,必须能够将技术链接在一起几次.
例如,假设我们想要扩展,lambda以便每次调用定义的函数时lambda,它在执行函数体之前打印"foo".我们可以通过以下方式执行此操作:
(define-syntax old-lambda lambda)
(define-syntax lambda
(syntax-rules ()
((_ args body ...)
(old-lambda args (display "foo") body ...))))
Run Code Online (Sandbox Code Playgroud)
我们还可以通过以下方式以另一种方式扩展它(例如,通过打印"bar"):
(define-syntax old-lambda-2 lambda)
(define-syntax lambda
(syntax-rules ()
((_ args body ...)
(old-lambda-2 args (display "bar") body ...))))
Run Code Online (Sandbox Code Playgroud)
最终结果是使用new定义的函数lambda将打印"foo",然后每次调用它们时都会显示"bar".
但是,除了用大量的方法来污染命名空间之外old-lambda-<x>,old-lambda-<x>每次我们这样做时都需要在源代码级别创建一个新的; 这不能自动化,因为您也不能gensym在语法定义中使用.因此,没有好的方法可以实现这种可扩展性; 唯一可行的解决方案是命名每个old-lambda-print-foo或类似的消歧,这显然不是一个万无一失的解决方案.(有关这可能失败的示例,请说代码的两个不同部分是扩展lambda为打印"foo";当然,它们都会命名它old-lambda-print-foo,瞧!lambda现在是无限循环.)因此,它会非常很高兴,如果我们能够以理想的方式做到这一点:
old-lambda-<x>在 Racket 中,您可以使用模块来做到这一点。您可以创建一个模块,重新导出除 Racket 之外的整个 Racket 语言lambda,并以名称 导出新宏lambda。我将展示一种排列代码的方法。
该foo-lambda模块定义并导出foo-lambda表单,该表单创建在应用时打印“foo\n”的过程。
(module foo-lambda racket
(define-syntax-rule (foo-lambda formals body ...)
(lambda formals (displayln "foo") body ...))
(provide foo-lambda))
Run Code Online (Sandbox Code Playgroud)
该racket-with-foo-lambda模块重新导出整个 Racket 语言,但它foo-lambda以名称提供lambda。
(module racket-with-foo-lambda racket
(require 'foo-lambda)
(provide (except-out (all-from-out racket) lambda)
(rename-out [foo-lambda lambda])))
Run Code Online (Sandbox Code Playgroud)
现在您可以用这种“新语言”编写模块:
(module some-program 'racket-with-foo-lambda
(define f (lambda (x) x))
(f 2))
(require 'some-program)
Run Code Online (Sandbox Code Playgroud)
请注意,这不会更改 的Racket 版本lambda,并且其他 Racket 形式仍然使用 Racketlambda绑定。例如,如果您将f上面的定义重写为(define (f x) x),那么 Racket'sdefine将扩展为 Racket's 的使用lambda,并且您将不会获得“foo”打印输出。
您可以链接扩展:每个扩展都在导入先前版本的模块中定义。例如,您的bar-lambda模块将导入该foo-lambda模块,等等。
事实上,Racket 在内部就是这样做的。编译器只能理解lambda位置参数,但 Racket 语言有一个lambda支持位置参数和关键字参数的 。Racket 语言的实现有一个模块,该模块用处理关键字参数的版本替换内置的lambdaand #%app(隐式用于处理函数应用程序语法)。