gpt4 book ai didi

inheritance - 可扩展的宏定义

转载 作者:行者123 更新时间:2023-12-03 23:07:06 25 4
gpt4 key购买 nike

灵感来自 comment thread关于函数而不是宏的相关问题。

有什么方法可以扩展一个 Scheme 语法定义,以便它可以在新定义中使用之前的语法定义?此外,这必须是可扩展的,也就是说,必须可以将技术链接在一起多次。

例如,假设我们要扩展 lambda这样每次使用 lambda 定义的函数被调用时,它会在执行函数体之前打印“foo”。我们可以通过以下方式做到这一点:

(define-syntax old-lambda lambda)

(define-syntax lambda
(syntax-rules ()
((_ args body ...)
(old-lambda args (display "foo") body ...))))

我们还可以通过执行以下操作以另一种方式扩展它(例如,通过打印“bar”):
(define-syntax old-lambda-2 lambda)

(define-syntax lambda
(syntax-rules ()
((_ args body ...)
(old-lambda-2 args (display "bar") body ...))))

最终结果是使用我们的新 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))
    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])))

    现在您可以用这种“新语言”编写模块:
    (module some-program 'racket-with-foo-lambda
    (define f (lambda (x) x))
    (f 2))
    (require 'some-program)

    请注意,这不会更改 lambda 的 Racket 版本。 ,而其他 Racket 形式仍然使用 Racket lambda捆绑。例如,如果您重写了 f 的定义。以上为 (define (f x) x) ,然后是 Racket 的 define将扩展到使用 Racket 的 lambda ,并且您不会得到“foo”打印输出。

    您可以链接扩展:每个扩展都定义在导入先前版本的模块中。例如,您的 bar-lambda模块将导入 foo-lambda模块等。

    事实上,Racket 在内部执行此操作。编译器只理解 lambda带有位置参数,但 Racket 语言有 lambda支持位置和关键字参数。 Racket 语言的实现有一个模块替换了内置的 lambda#%app (隐式用于处理函数应用程序语法)与处理关键字参数的版本。

    关于inheritance - 可扩展的宏定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23898908/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com