【问题标题】:Introducing a Named Variable with Syntax Rules使用语法规则引入命名变量
【发布时间】:2018-04-23 13:18:17
【问题描述】:

我正在尝试使用语法规则编写一个超小型的面向对象系统,主要是为了学习它。无论如何,我正在尝试引入一个“this”变量。这是我想做的事情:

(oo-class Counter 
    (
        (attr value 0)
        (attr skip 1)
    )
    (
        (method (next) (set! value (+ value skip)) value)
        (method (nextnext) (this 'next) (this 'next))
        (method (set-value newval) (set! value newval))
        (method (set-skip newskip) (set! skip newskip))
    )
)

(define c (Counter))
((c 'set-value) 23)
((c 'next))
((c 'nextnext))

除了“this”之外,我可以让一切正常工作。似乎语法规则不允许变量引入。我认为我可以通过将其定义为语法规则中的文字之一来获得它,但这似乎不起作用。

下面是我的面向对象系统:

(define-syntax oo-class
    (syntax-rules (attr method this)
        (
            (oo-class class-name 
                ((attr attr-name initial-val) ...) 
                ((method (meth-name meth-arg ...) body ...) ...))
            (define class-name 
                (lambda () 
                    (letrec
                        (
                            (this #f)
                            (attr-name initial-val)
                            ...
                            (funcmap 
                                    (list 
                                        (cons (quote meth-name) (cons (lambda (meth-arg ...) body ...) '()))
                                        ...
                                    )
                            )
                        )
                        (set! this (lambda (methname)
                            (cadr (assoc methname funcmap))
                        ))
                        this
                    )
                )
            )
        )
    )
)

这适用于除 'nextnext 之外的所有内容,当它尝试引用“this”时会出错。

这是正确的方法吗?还有其他方法可以做到这一点吗?我承认这有点不卫生,但这至少不是指定文字的一部分吗?

我在 Chicken Scheme 和 DrRacket 的 R5RS 模式下都试过这个(其他模式会抱怨“this”)。

以下是整个文件。你可以用“csi object.scm”在Chicken上运行它

https://gist.github.com/johnnyb/211e105882248e892fa485327039cc90

我还尝试使用 let-syntax 并使用 (this) 作为语法说明符来引用 (this) 变量。但是,据我所知,它并没有让我在语法重写中直接访问我自己制作的变量。

奖励问题:查看语法规则转换结果以进行调试的简单方法是什么?有没有办法让鸡肉(或其他东西)进行转换并吐出结果?我在 DrRacket 上尝试了一些东西,但它在 R5RS 模式下不起作用。

【问题讨论】:

    标签: macros scheme chicken-scheme syntax-rules


    【解决方案1】:

    我承认这有点不卫生,但这不是指定文字的至少一部分吗?

    不,文字存在,因此您可以在关键字上进行字面匹配,例如cond 子句中的=>else。它仍然是卫生的,因为如果 =>else 在词法上绑定到某个值,则具有优先权:

    (let ((else #f))
      (cond (else (display "hi!\n")))) ;; Will not print
    

    现在,您可以编写一个非常乏味的宏,在任何可能的位置和扩展中的嵌套级别匹配 this,但这永远不会完成,它也不会在词法上嵌套.

    可以使用众所周知的 Petrofsky extraction 来做你想做的事,但这是对语法规则的彻底和彻底的破解和滥用,它不起作用(始终如一地)存在跨实现的模块(例如,恰好在 CHICKEN 中,我们有一个 complaint,我们不小心“破坏”了这个功能)。

    我的建议是编写一个语法规则宏,该宏在其输入中接受一个标识符,该标识符将绑定到当前对象,然后编写一个微不足道的不卫生宏,该宏使用硬编码标识符 this 调用另一个宏输入。

    查看语法规则转换结果以进行调试的简单方法是什么?有没有办法让鸡肉(或其他东西)进行转换并吐出结果?我在 DrRacket 上尝试了一些东西,但它在 R5RS 模式下不起作用。

    在 csi 中,你可以使用,x (macro-call),但它只会做一级扩展。

    在每个 Scheme 实现中都有效的一个常见技巧是更改宏定义以引用其输出。所以,它不是扩展到(foo),而是扩展到'(foo)。这样,您只需调用 REPL 中的宏并立即查看其结果。

    【讨论】:

    • 感谢您的回复!我发现了一些有趣的东西.... 1) 虽然我的代码 没有 像发布的那样工作,但如果我按照你的“引用”技巧来查看输出,然后 然后复制/粘贴结果,它确实工作了!我不知道这是方案的标准部分还是鸡方案的奇怪之处。 2)我利用它来发挥我的优势。我做了一个“让”来将引用技巧的结果分配给一个变量,然后对结果做了一个“评估”。中提琴,成功了!
    • 这个eval 技巧有效,因为所有语法信息都已被剥离。在您的原始代码中,您有 (let ((this #f)) ...);它将被转换为(let ((this123 #f)) ...) 之类的东西,并且在宏定义中出现的任何其他this 都将被转换为this123,而用户提供的this 将被转换为(比如)this456。但是,当您评估引用的输出时,所有这些 this 标识符都将被“扁平化”(去除语法信息)并因此折叠成相同的。一般来说,这不是一个好主意:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多