Это проблема, которая время от времени натыкалась на меня, и мне интересно, может ли кто-нибудь здесь помочь.
У меня есть модель 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?
Спасибо за чтение!