PLT Redex: параметризация определения языка

Это проблема, которая время от времени натыкалась на меня, и мне интересно, может ли кто-нибудь здесь помочь.

У меня есть модель PLT Redex языка, называемая lambdaLVar, которая является более или менее разновидным нетипизированным лямбда-исчислением в саду, но распространяется с помощью хранилища, содержащего "переменные решетки" или LVars. LVar - это переменная, значение которой может только увеличиваться со временем, когда значение "увеличения" задается частично упорядоченным множеством (ака решетки), которое указывает пользователь языка. Поэтому lambdaLVar - это действительно семейство языков - создайте его с помощью одной решетки, и вы получите один язык; с другой решеткой, и вы получите другую. Вы можете посмотреть код здесь; важный материал находится в lambdaLVar.rkt.

В определении lambdaLVar на бумаге определение языка параметризуется этой заданной пользователем решеткой. В течение долгого времени я хотел сделать такую ​​же параметризацию в модели Redex, но до сих пор я не мог понять, как это сделать. Часть проблемы состоит в том, что грамматика языка зависит от того, как пользователь создает экземпляр решетки: элементы решетки становятся терминалами в грамматике. Я не знаю, как выразить грамматику в Redex, которая является абстрактной по решетке.

Тем временем я пытался сделать lambdaLVar.rkt модульным, насколько мог. Язык, определенный в этом файле, специализируется на конкретной решетке: натуральные числа с max как операция с наименьшей верхней границей (lub). (Или, что то же самое, натуральные числа, упорядоченные с помощью <=. Это очень скучная решетка.) Единственными частями кода, специфичными для этой решетки, являются строка (define lub-op max) около вершины и natural, появляющаяся в грамматике, (Там a lub metafunction, который определен в терминах указанной пользователем функции lub-op. Последний является просто функцией Racket, поэтому lub должен выйти из Racket для вызова lub-op.)

Невозможность фактически указать lambdaLVar таким образом, который является абстрактным по выбору решетки, кажется, что я должен был бы написать версию lambdaLVar с самыми голыми решетками - просто Bot и Top элементы, где Bot <= Top - и затем используйте define-extended-language, чтобы добавить больше материала. Например, я мог бы определить язык, называемый lambdaLVar-nats, который специализирован для решетки naturals, описанной мной:

;; Grammar for elements of a lattice of natural numbers.
(define-extended-language lambdaLVar-nats
  lambdaLVar
  (StoreVal .... ;; Extend the original language
            natural))

;; All we have to specify is the lub operation; leq is implicitly <=
(define-metafunction/extension lub lambdaLVar-nats
  lub-nats : d d -> d
  [(lub-nats d_1 d_2) ,(max (term d_1) (term d_2))])

Затем, чтобы заменить два редукционных отношения slow-rr и fast-rr, которые у меня были для lambdaLVar, я мог бы определить пару оболочек:

(define nats-slow-rr
  (extend-reduction-relation slow-rr
                             lambdaLVar-nats))

(define nats-fast-rr
  (extend-reduction-relation fast-rr
                             lambdaLVar-nats))

Мое понимание из документации на extend-reduction-relation заключается в том, что оно должно переосмысливать правила в slow-rr и fast-rr, но используя lambdaLVar-nats. Объединив все это, я попытался запустить набор тестов, который у меня был с одним из новых расширенных отношений сокращения:

> (program-test-suite nats-slow-rr)

Первое, что я получаю, это жалоба о нарушении контракта: small-step-base: input (((l 3)) new) at position 1 does not match its contract. Контрактная строка малой шаговой базы - это просто #:contract (small-step-base Config Config), где Config - это нетерминал грамматики, который имеет новое значение, если он интерпретируется под lambdaLVar-nats, чем при lambdaLVar, из-за специфического материала решетки. В качестве эксперимента я избавился от контрактов на small-step-base и small-step-slow.

Тогда я смог фактически запустить 19 тестовых программ, но 10 из них терпят неудачу. Возможно, неудивительно, что все те, которые терпят неудачу, - это программы, которые каким-то образом используют LVAR с натуральным числом. (Остальные - это "чистые" программы, которые вообще не взаимодействуют с хранилищем LVARS.) Таким образом, тесты, которые терпят неудачу, являются именно теми, которые используют расширенную грамматику.

Итак, я продолжал следить за кроличьей дырой, и, похоже, Redex хочет, чтобы я расширил все существующие формы суждений и метафрукты, которые будут связаны с lambdaLVar-nats, а не lambdaLVar. Это имеет смысл, и, кажется, это нормально работает для суждений, насколько я могу судить, но с метафайлами у меня возникают проблемы: я хочу, чтобы новый метафорум перегрузил старое одноименное имя (потому что существующие формы суждения используют его), и, похоже, нет способа сделать это. Если мне нужно переименовать метафунты, это победит цель, потому что мне все равно придется писать все новые суждения. Я полагаю, что то, что я хочу, является своего рода поздним связыванием вызовов metafunction!

Мой вопрос в двух словах: Есть ли какой-либо путь в Redex для параметризации определения языка так, как я хочу, или для расширения определения языка таким образом, который будет делать то, что Я хочу? Будет ли мне просто писать макросы, генерирующие Redex?

Спасибо за чтение!

Ответ 1

Я спросил список рассылки пользователей Racket; нить начинается здесь. Чтобы обобщить итоговое обсуждение: в Redex, поскольку он стоит сегодня, ответ нет, нет возможности параметризовать определение языка так, как я хочу. Однако это должно быть возможным в будущей версии Redex с модульной системой, которая сейчас работает.

Он также не работает, чтобы попытаться использовать существующие формы расширения Redex (define-extended-language, extend-reduction-relation и т.д.) так, как я пытался это сделать, потому что - как я обнаружил - исходные метафунции не переводите транзитно на использование расширенных языков. Но модульная система, по-видимому, также поможет в этом, потому что это позволит вам комбинировать метафунции, суждения и отношения сокращения и одновременно расширять их (см. Обсуждение здесь).

Итак, на данный момент, действительно, нужно написать макрос, генерирующий Redex. Что-то вроде этого работает:

(define-syntax-rule (define-lambdaLVar-language name lub-op lattice-values ...)
  (begin
    ;; Entire original Redex model goes here, with `natural` replaced with
    ;; `lattice-values ...`, and instances of `...` replaced with `(... ...)`
))

И тогда вы можете создавать экземпляры конкретных решеток, например,

(define-lambdaLVar-language lambdaLVar-nat max natural)

Я надеюсь, что Redex скоро получит модули, но пока это работает хорошо.