Введение именованной переменной с правилами синтаксиса

Я пытаюсь написать супер-крошечную объектно-ориентированную систему с синтаксическими правилами, в основном, просто чтобы изучить ее. Во всяком случае, я пытаюсь ввести переменную "это". Вот что я хотел бы сделать:

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

Я могу заставить все работать, кроме "этого". Кажется, что синтаксические правила не позволяют вводить переменные. Я думал, что смогу получить это, определив его как один из литералов в синтаксических правилах, но это, похоже, не работает.

Ниже моя объектно-ориентированная система:

(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 (другие режимы жалуются на "это").

Ниже весь файл. Вы можете запустить его на Chicken с помощью всего лишь "csi object.scm"

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

Я также пытался использовать let-синтаксис и использовать (this) в качестве спецификатора синтаксиса для ссылки на (this) переменную. Но, насколько я мог судить, это не позволяло мне напрямую получить доступ к переменной моего собственного создания в рамках переписывания синтаксиса.

БОНУСНЫЙ ВОПРОС: Какой простой способ увидеть результат преобразования правил синтаксиса для отладки? Есть ли какой-нибудь способ заставить цыпленка (или что-то еще) сделать преобразование и выплюнуть результат? Я попробовал кое-что на DrRacket, но он не работает в режиме R5RS.

1 ответ

Решение

Я понимаю, что это немного негигиенично, но разве это не является частью определения литералов?

Нет, литералы существуют, поэтому вы можете сопоставлять буквально по ключевым словам, как, например, => или else в cond пункт. Это все еще гигиенично, потому что если => или же else лексически связан с некоторым значением, которое имеет приоритет:

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

Теперь вы можете написать очень утомительный макрос, который соответствует this на любом возможном месте и уровне вложенности в расширении, но это никогда не будет полным, и оно также не будет лексическим.

Можно сделать то, что вы пытаетесь сделать, используя то, что стало известно как извлечение Петрофски, но это полный и полный взлом и злоупотребление синтаксическими правилами, и он не работает (последовательно) при наличии модулей в разных реализациях (например, именно в CHICKEN у нас была жалоба на то, что мы случайно "сломали" эту функцию).

Я бы предложил написать макрос синтаксических правил, который принимает идентификатор на входе, который будет привязан к текущему объекту, а затем написать один тривиальный негигиеничный макрос, который вызывает этот другой макрос с жестко закодированным идентификатором. this в качестве ввода.

Какой простой способ увидеть результат преобразования правил синтаксиса для отладки? Есть ли какой-нибудь способ заставить цыпленка (или что-то еще) сделать преобразование и выплюнуть результат? Я попробовал кое-что на DrRacket, но он не работает в режиме R5RS.

В CSI, вы можете использовать ,x (macro-call), но он сделает только один уровень расширения.

Обычный трюк, который работает в каждой реализации Scheme, - это изменение определения макроса для цитирования его выходных данных. Таким образом, это расширяется, чтобы не (foo) но '(foo), Таким образом, вы можете просто вызвать макрос в REPL и сразу увидеть его результат.

Другие вопросы по тегам