Академический Документы
Профессиональный Документы
Культура Документы
rozplohas_da_sertificirovannaya-semantika-yazyka-minikanren_136783
rozplohas_da_sertificirovannaya-semantika-yazyka-minikanren_136783
УЧРЕЖДЕНИЕ
ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ
«НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ УНИВЕРСИТЕТ
«ВЫСШАЯ ШКОЛА ЭКОНОМИКИ»
Факультет Санкт-Петербургская школа физико-математических и
компьютерных наук
1. Обзор 5
1.1. Язык MiniKanren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2. Денотационная семантика языка MiniKanren . . . . . . . . . . . . . . . . 9
1.3. Существующие семантики логических языков
программирования . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Заключение 35
Список литературы 36
2
Введение
MiniKanren — минималистичный встраиваемый язык логического программирова-
ния, свободный от побочных эффектов. Вычисления в нем основаны на идее поиска с
чередованием (interleaving search [2]), важной и известной характеристикой которого
является полнота (то есть свойство, что любой ответ, удовлетворяющий программе-
запросу, будет найден за конечное время). Чистота языка (в отношении побочных
эффектов) и специфические свойства поиска позволяют эффективно использовать
MiniKanren для реализации парадигмы “реляционного программирования”: функцио-
нальные программы начинают рассматриваться и конструироваться как математи-
ческие отношения между аргументами и результатом, что позволяет производить
обратимые вычисления. Эта эффективность (а также простота встраивания языка)
обеспечивает его популярность: существует более 100 его реализаций для более чем
40 различных языков1 .
Даже в академических текстах язык и его аспекты обычно представляются нефор-
мально. Главная книга [11], являющаяся введением в язык, описывает его с помо-
щью последовательности усложняющихся примеров программ. Статьи [6, 12, 29, 31],
описывающие различные расширения языка, представляют их реализацией на языке
Scheme. При таком подходе специфицировать язык и его расширения для каждой ре-
ализации нужно отдельно, полагаясь на знание языка реализации у читателя. Кроме
того, анализ программ и доказательства свойств языка, опирающиеся на такую спе-
цификацию, являются крайне сложными (так как необходимо учитывать множество
деталей исполнения программ в языке реализации) и могут считаться достоверными
только в рамках конкретной реализации.
Альтернативным общепринятым подходом к спецификации, который решает ука-
занные проблемы, является определение операционной семантики языка — абстракт-
ного описания процесса исполнения программ, которому должны соответствовать
конкретные реализации. В литературе уже описывались несколько вариантов такой
семантики для MiniKanren (см. обзор в разделе 1.3), однако все они имеют важное
ограничение: они не отражают свойств поиска с чередованием, поэтому являются
значительным упрощением по сравнению с общепринятым пониманием языка.
В данной работе будет представлена операционная семантика, свободная от дан-
ного ограничения, и доказано определяющее свойство поиска — его полнота — путем
установления эквивалентности этой операционной семантики и денотационной семан-
тики языка (которая задает математическую модель программы).
При этом, как это часто бывает для сколько-нибудь реальных языков програм-
мирования, описание и доказательства требуют особой аккуратности и являются до-
вольно сложными для проверки, потому что доказательства включают большое чис-
1
http://minikanren.org/#implementations
3
ло случаев и деталей, за которыми нужно следить (а также потому, что происходит
работа с бесконечными математическими объектами). Поэтому для обеспечения на-
дежности результата мы изначально задаемся целью создания “сертифицированной
семантики” — семантики, определение которой будет формализовано и все доказа-
тельства верифицированы в некоторой среде автоматической проверки доказательств
(мы используем Coq [3]). Это также позволит нам, используя механизм извлечения
программ из доказательств, получить готовую реализацию MiniKanren, гарантиро-
ванно соответствующую семантике и обладающую доказанными свойствами.
Постановка задачи
Целью данной работы является определение и демонстрация применения опера-
ционной семантики языка MiniKanren, задающей поиск с чередованием.
В рамках данной цели выделены следующие задачи.
4
1. Обзор
В этом разделе будет представлено описание языка MiniKanren, включая его син-
таксис и денотационную семантику. Также будет дан обзор предшествующих работ,
посвященных описанию различных семантик (в том числе сертифицированных) как
для языка MiniKanren, так и в более широком контексте логического программиро-
вания.
5
x ∈ X = {x, y, z, . . . } синтаксические переменные
α ∈ A = {γ1 , γ2 , γ3 , . . . } логические переменные
Ck ∈ C = {N il0 , Cons2 , . . . } конструкторы с указанной арностью
t ∈ T = x | α | C k (t1 , . . . , tk ) термы
rk ∈ R = {append3 , reverse2 , . . . } имена отношений с указанной арностью
g ∈ G = цели
t1 ≡ t2 унификация
| g1 ∧ g2 конъюнкция
| g1 ∨ g2 дизъюнкция
| fresh x . g введение свежей логической переменной
| rk (t1 , . . . , tk ) вызов отношения
p ∈ P = {riki = λ xi1 . . . xiki . gi ; }∗ g программы
6
x [t/x] = t
y [t/x] = y, y ̸= x
α [t/x] = α
C k (t1 , . . . , tk ) [t/x] = C k (t1 [t/x], . . . , tk [t/x])
(t1 ≡ t2 ) [t/x] = t1 [t/x] ≡ t2 [t/x]
(g1 ∧ g2 ) [t/x] = g1 [t/x] ∨ g2 [t/x]
(g1 ∨ g2 ) [t/x] = g1 [t/x] ∧ g2 [t/x]
(fresh x . g) [t/x] = fresh x . g
(fresh y . g) [t/x] = fresh y . (g [t/x]), y ̸= x
k
(r (t1 , . . . , tk )) [t/x] = rk (t1 [t/x], . . . , tk [t/x])
7
• Для вызова функции rk (t1 , . . . , tk ) в тело функции подставляются данные аргу-
менты и полученная цель применяется к состоянию.
8
Важное отличие в определении от соответствующих функций на функциональном
языке состоит в том, что задаваемые нами отношения имеют на один аргумент боль-
ше. Этот последний аргумент соответствует результату функции на функциональном
языке. В остальном же отношения строятся по такому же принципу, что и функции:
в обоих отношениях разбираются два случая пустого/непустого списка-аргумента, и
во втором случае производится рекурсивный вызов для хвоста списка (для простоты
приведено отношение, соответствующее тривиальной версии функции разворачива-
ния, но для хвосто-рекурсивной версии отношение можно построить точно так же).
Наличие результата в списке аргументов позволяет нам вызывать функцию не только
“в прямую сторону” (передавать аргументы-константы и искать результат), но и бо-
лее интересным образом, например требуя любые совпадающие аргумент и результат,
как в нашем запросе.
В результате исполнения данной программы мы получим бесконечный поток под-
становок, в которых переменной γ1 будут соответствовать следующие значения.
γ1 7→ Nil
γ1 7 → Cons (γ2 , Nil)
γ1 7 → Cons (γ2 , Cons (γ2 , Nil))
γ1 7 → Cons (γ2 , Cons (γ5 , Cons (γ2 , Nil)))
...
При этом переменные справа не связаны в результирующей подстановке, то есть
соответствуют произвольному константному терму (но вместо всех вхождений одной
переменной должен быть подставлен один и тот же терм). Таким образом, каждый
ответ задает в точности множество всех палиндромов определенной длины.
9
ваются отношения, для которых имеется определение в программе, и что при вызове
указывается правильное количество аргументов. Денотационной семантикой програм-
мы тогда будет денотационная семантика цели-запроса.
В качестве математической интерпретации целей естественно взять теоретико-мно-
жественные отношения как множество подходящих значений для логических пере-
менных, встречающихся в программе. Мы будем делать по сути именно это, но для
удобного композиционного построения наша семантика будет сопоставлять значения
всем логическим переменным, а не только встречающимся в программе (при этом, как
мы покажем позже, в результате только значения встречающихся переменных будут
важны). Таким образом доменом нашей денотационной семантики будут множества
означивающих функций, сопоставляющих каждой логической переменной некоторый
константный терм.
JgK ∈ 2A→D
f: T → D
f(α) = f(α)
k
f(C (t1 , . . . , tk )) = Ck (f(t1 ), . . . , f(tk ))
Кроме того, нам потребуется операция обобщения переменной в множестве означива-
ющих функций. Эта операция берет все функции из множества и позволяет заменить
значение данной переменной на произвольное.
F ↑ α = {f[α ← d] | f ∈ F, d ∈ D}
10
Jt1 ≡ t2 K = {f : A → D | f (t1 ) = f (t2 )}
Jg1 ∨ g2 K = Jg1 K ∪ Jg2 K
Jg1 ∧ g2 K = Jg1 K ∩ Jg2 K
Jfresh x . gK = (Jg [α/x]K) ↑ α, для α ̸∈ F V (g)
Jrk (t1 , . . . , tk )K = Jg [t1 /x1 , . . . , tk /xk ]K, для (rk = λ x1 . . . xk . g) ∈ Γ
1. f2 (α2 ) = f1 (α1 )
2. ∀α : α ̸= α1 ∧ α ̸= α2 , f2 (α) = f1 (α)
11
Другое важное свойство определенной так денотационной семантики, которое мы
обещали доказать, состоит в том, что принадлежность означивающей функции се-
мантике цели зависит только от значений функции на свободных переменных этой
цели. Мы будем называть это замкнутостью денотационной семантики.
f1 ∈ JgK ⇔ f2 ∈ JgK.
12
может использоваться в качестве реального интерпретатора языка, но её связь с дву-
мя другими не устанавливается.
Таким образом, ни одна из предыдущих известных нам семантик не описывает по-
иска с чередованием, поэтому не пригодна для доказательства его главного свойства —
полноты — и получения сертифицировано корректного интерпретатора. Единственное
известное нам относительно строгое (но не сертифицированное) доказательство этого
свойства представлено в статье [28], однако оно дается только в рамках конкретной
реализации поиска на языке Scheme, и, кроме того, полнота поиска понимается там
как сохранение всех ответов при смешивании потоков, то есть в более узком смысле,
чем наше понимание полноты здесь — как соответствие множества найденых ответов
математической модели программы.
13
2. Операционная семантика для поиска
с чередованием
В этом разделе будет описана новая операционная семантика языка MiniKanren,
отражающая исполнение программ в некоторой реальной реализации языка, в кото-
рой осуществляется поиск решений с чередованием.
Мы зададим семантику в стандартной форме системы переходов с пометками
(labeled transition system, LTS [14]). А именно, мы определим множество состояний по-
иска и зададим переходы между состояниями, некоторые из которых будут помечены
ответом, найденым на данном шаге. Исполнение программы тогда будет задаваться
путем в таком графе из некоторого начального состояния, а пометки на переходах в
этом пути будут соответствовать ответам, которые находит поиск. При определении
семантики мы снова зафиксируем программу с некоторым произвольным набором
определений отношений Γ = {ri = λ xi1 . . . xiki . gi }i .
Множество нетерминальных состояний определяется индуктивно следующим об-
разом:
s ∈ S = ⟨g, σ, n⟩ | s1 ⊕ s2 | s ⊗ g.
ŝ ∈ Ŝ = ♢ | s
14
которых определена подстановка, а VRan (σ) — множество переменных, встречаю-
щихся в значениях подстановки).
• ⋄ согласовано;
15
⟨t1 ≡ t2 , σ, n⟩ −
→ ♢, ∄ mgu (t1 σ, t2 σ) [UNIFYFAIL]
(σδ,n)
⟨t1 ≡ t2 , σ, n⟩ −−−→ ♢, mgu (t1 σ, t2 σ) = δ [UNIFYSUCCESS]
⟨g1 ∨ g2 , σ, n⟩ −
→ ⟨g1 , σ, n⟩ ⊕ ⟨g2 , σ, n⟩ [DISJ]
⟨g1 ∧ g2 , σ, n⟩ −
→ ⟨g1 , σ, n⟩ ⊗ g2 [CONJ]
⟨fresh x . g, σ, n⟩ −
→ ⟨g [αn /x], σ, n + 1⟩ [FRESH]
(rk = λ x1 . . . xk . g) ∈ Γ
[INVOKE]
⟨rk (t1 , . . . , tk ), σ, n⟩ −
→ ⟨g [t1 /x1 ] . . . [tki /xki ], σ, n⟩
s1 −
→♢
[DISJSTOP]
(s1 ⊕ s2 ) −
→ s2
r
s1 −
→♢
r [DISJSTOPANS]
(s1 ⊕ s2 ) −
→ s2
s1 −→ s′1
[DISJSTEP]
→ (s2 ⊕ s′1 )
(s1 ⊕ s2 ) −
r
→ s′1
s1 −
r [DISJSTEPANS]
→ (s2 ⊕ s′1 )
(s1 ⊕ s2 ) −
s−→♢
[CONJSTOP]
(s ⊗ g) −
→♢
(σ,n)
s −−−→ ♢
[CONJSTOPANS]
(s ⊗ g) −
→ ⟨g, σ, n⟩
s−→ s′
[CONJSTEP]
(s ⊗ g) −
→ (s′ ⊗ g)
(σ,n)
s −−−→ s′
[CONJSTEPANS]
(s ⊗ g) →
− (⟨g, σ, n⟩ ⊕ (s′ ⊗ g))
16
Для частично вычисленной конъюнкции ⊗ шаги всегда делаются в левом состоя-
нии, а любой полученный при этом ответ (подстановка и счетчик переменных) ком-
понуется в новое состояние с правой целью и начинает вычисляться параллельно с
данной частично вычисленной конъюнкцией (для этого они объединяются с помо-
щью ⊕). Когда вычиление левого состояния доходит до терминального состояния,
вычисление частичной конъюнкции завершается.
Несложно заметить, что данная система переходов является детерминированной:
из любого нетерминального состояния существует ровно один переход. Таким обра-
зом, для любой программы действительно всегда существует единственный путь из
начального состояния, задающий её исполнение. Причем мы описываем исполнение
как завершающихся программ (если путь приходит в терминальное состояние), так и
незавершающихся (если путь бесконечен). Мы будем обозначать множество ответов
на таком пути из состояния ŝ как T r(ŝ).
Также легко показать, что состояния после перехода остаются согласованными.
17
Кроме того, мы можем также легко описать условие завершимости исполнения
дизъюнкции.
18
3. Эквивалентность операционной и денотационной
семантик
В этом разделе мы докажем эквивалентность определенной в предыдущем разделе
операционной семантики языка MiniKanren и его денотационной семантики, описан-
ной в разделе 1.2.
Таким образом мы формализуем и докажем полноту поиска с чередованием, по-
тому что операционная семантика задает ответы, которые будут найдены конкретно
этим поиском, а денотационная семантика задает все ответы, лежащие в математи-
ческой модели программы, построенной по запросу в ней.
Но прежде чем мы сможем сформулировать эквивалентность этих двух семантик,
нам необходимо установить соответствия между разными формами представления
ответов в них: для операционной семантики это подстановка, а для денотационной —
множество означивающих функций.
Для этого заметим, что любую подстановку σ можно расширить до означивающей
функции, которая удовлетворяет ограничениям на значения переменных в σ, взяв
композицию σ и произвольной означивающей функции. Тогда мы можем определить
денотационный аналог подстановки (соответствующее ей множество означивающих
функций) следующим образом:
JσK = {f ◦ σ | f : A 7→ D}.
∪
JŝKop = JσK
(σ,n)∈T r(ŝ)
Теорема может быть доказана по индукции, но сначала нам нужно обобщить её,
чтобы индукционная гипотеза стала достаточно сильной для доказательства. Для
этого мы обобщим определение денотационной семантики целей на произвольные со-
стояния. Определение приведено на Рис. 6. Оно кажется достаточно естественным,
19
J♢K = ∅
J⟨g, σ, n⟩K = JgK ∩ JσK
Js1 ⊕ s2 K = Js1 K ∪ Js2 K
Js ⊗ gK = JsK ∩ JgK
хотя его интуитивная интерпретация не имеет для нас значения — это определение
нужно только для того, чтобы индуктивное доказательство сработало.
Используя эту определение мы формулируем обобщенную теорему о корректности
для произвольных согласованных состояний.
JsKop ⊆ JsK.
JσK ⊆ JsK.
JŝK ⊆ JsK.
20
означивающих функций на переменных занятых в самом начале (включая все сво-
бодные переменные запроса). Такое уточнение формулировки никак не противоречит
нашей мотивации доказать полноту поиска в языке, так как ответы в MiniKanren
предоставляются только для переменных из запроса.
J•Kl : G → 2A→D .
Jriki (t1 , . . . , tki )Kl+1 = Jgi [t1 /xi1 , . . . , tki /xiki ]Kl .
JgK0 = ∅.
21
Лемма 11. Для любого согласованного состояния ⟨g, σ, n⟩, для любого уровня l
22
4. Формализация теории в Coq
Вся теория для языка MiniKanren, описанная в предыдущих разделах была форма-
лизована2 в среде интерактивных докзательств теорем Coq: синтаксис языка, денота-
ционная и операционная семантики и доказательство их эквивалентности. Код форма-
лизации находится в приведеном репозитории в папке src. Там же в папке extracted
находится код корректного по построению интерпретатора языка MiniKanren, извле-
каемый из этой формализации. В данном разделе будет поэтапно описана данная
формализация.
Формализация в целом довольно точно следует определениям и утверждениям,
приведенным в предыдущих разделах. Однако на язык накладывается одно неприн-
ципиальное ограничение, которое при этом значительно упрощает работу с ним в
Coq: всем конструкторам в термах разрешается иметь только арности равные ну-
лю или двум, а все задаваемые в программе отношения должны иметь ровно один
аргумент. Это ограничение никак не влияет на выразительность языка, так как после-
довательность термов произвльной длины всегда может быть закодирована списком,
используя конструкторы Nil0 и Cons2 . Кроме того, в формализации на Coq мы можем
отказаться от различения синтаксичених и логических переменных: явным образом
в термах задаются только логические переменные, а для обращения со связывани-
ем синтаксических переменных используется механизм синтаксиса высшего порядка
(higher-order abstract syntax [23]).
Но прежде чем перейти к формализации понятий языка MiniKanren, нам необхо-
димо сначала формализовать все базовые понятия из теории унификации, которые
используются в языке и приведенных семантиках.
23
Inductive term : Set :=
| Var : name → term
| Cst : name → term
| Con : name → term → term → term.
Для термов мы задаем множество свободных переменных функцией, вычисляю-
щей его (она возвращает множество в форме Lists.ListSet.set). Также мы опреде-
ляем тип константных термов как зависимую пару, накладывая на обычные термы
условие отсутствия свободных переменных.
Definition ground_term : Set := {t : term | fv_term t = var_set_empty}.
24
и его определяющих свойств мы по точно тем же причинам не можем воспользоваться
обычной структурной индукцией.
Стандартным подходом для решения этой проблемы, который используется в част-
ности в работах [4, 15, 22, 25], является задание некоторой метрики на аргументах
функции вычисления MGU (обычно базирующейся на высоте термов и количестве
свободных переменных в них) и использование фундированной рекурсии (well-founded
recursion) при определении. Мы тоже используем подход такого рода. Конкретно, мы
отдельно определяем структурно-рекурсивную функцию, которая производит один
шаг унификации (находит переменную и неравный ей терм на соответствующих ме-
стах в аргументах и добавляет это связывание в унификатор) и доказываем, что после
каждого такого успешного шага число свободных переменных в термах (это наш про-
стой порядок) строго уменьшается.
После этого мы можем использовать фундированную индукцию (well-founded in-
duction) с указанным порядком для доказательства существования уникального ре-
зультата для любой пары аргументов и определяющих свойств этого результата,
которые мы будем использовать в дальнейших доказательствах: если вычисление
MGU успешно, то результирующая подстановка действительно унифицирует термы
(mgu_unifies) и является наиболее общей с таким свойством (mgu_most_general),
если же вычисление заканчивается неудачей, то унификаторов данных термов не су-
ществует (mgu_non_unifiable).
25
Определение отношения в программе отражает упомянутое выше ограничение на
один аргумент.
Definition rel : Set := term → goal.
Как видно из определений выше для обращения со связываниями синтаксических
переменных мы пользуемся синтаксисом высшего порядка. Мы предпочли его синтак-
сису первого порядка, потому что он дает нам возможность использовать подстановку
и индукционный принцип для целей, которые предоставляет Coq. Кроме того, иметь
только один тип явно задаваемых переменных гораздо проще. С другой стороны, с
синтаксисом высшего порядка нам приходится явно требовать некоторые ограниче-
ния на наши синтаксические категории, которые в случае синтаксиса первого порядка
были бы выполнены всегда.
А именно, мы должны потребовать, чтобы все связывания переменных были “кон-
систентными”, то есть чтобы при подстановке разных переменных в это связывание
результаты были одинаковы с точностью до переименования этих переменных (при
условии, что переменные свободны в теле связывания). Эта излишняя неограничен-
ность является известной проблемой синтаксиса высшего порядка и к ней обращается
ранняя работа посвященная его использованию в Coq [10], называя её наличием экзо-
тических термов (exotic terms). Для её решения там вводится специальный предикат,
исключающий экзотические термы. Так же поступим и мы.
Формальное определение стандартного переименования переменных оказалось до-
вольно сложной задачей для нашего языка в случае fresh конструкций, поэтому мы
ограничимся ослабленной версией переименования, которая оперирует только с несво-
бодными в цели переменными, чего будет достаточно для нашего случая.
(* Weak version of a variable renaming *)
Inductive renaming (old_x : name) ( new_x : name) : goal → goal → Prop :=
...
| rFreshNFV : ∀ fg,
(~ is_fv_of_goal old_x (Fresh fg)) →
renaming old_x new_x ( Fresh fg) ( Fresh fg)
| rFreshFV : ∀ fg rfg,
( is_fv_of_goal old_x (Fresh fg)) →
( ∀ y, (~ is_fv_of_goal y (Fresh fg)) →
renaming old_x new_x ( fg y) ( rfg y)) →
renaming old_x new_x ( Fresh fg) ( Fresh rfg)
...
Тогда консистентность целей и отношений может быть определена следующим
образом.
26
Definition consistent_binding (b : name → goal) : Prop :=
∀ x y, (~ is_fv_of_goal x (Fresh b)) → renaming x y (b x) ( b y).
Inductive consistent_goal : goal → Prop := ...
Definition consistent_function (f : term → goal) : Prop :=
∀ a1 a2 t, renaming a1 a2 ( f t) ( f ( apply_subst [( a1, Var a2)] t)).
Definition consistent_rel (r : rel) : Prop :=
∀ ( arg : term), consistent_goal (r arg) ∧ consistent_function r.
В коде выше предикат consistent_goal индуктивно проверяет, что все связы-
вания в цели являются консистентными, а применение подстановки в определении
consistent_function используется для переименования переменной.
Кроме консистентности связываний, мы должны явно потребовать отсутствия
несвязанных переменных в целях.
Definition closed_goal_in_context (c : list name) ( g : goal) : Prop :=
∀ n, is_fv_of_goal n g → In n c.
Definition closed_rel (r : rel) : Prop :=
∀ ( arg : term), closed_goal_in_context (fv_term arg) (r arg).
Используя эти два требования, мы фиксируем здесь в виде аксиомы программу
с произвольным набором именованных определений отношений, который мы будем
использовать далее на протяжении нашей формализации. Наличие целей-неудач поз-
воляют нам задать это окружение в виде всюду определенной функции.
Definition def : Set := {r : rel | closed_rel r ∧ consistent_rel r}.
Definition spec : Set := name → def.
Axiom Prog : spec.
27
Здесь же мы определяем нашу вспомогательную ограниченную семантику целей
из раздела 3 с помощью аналогичного отношения in_denotational_sem_lev_goal и
показываем её взаимосвязь с обычной семантикой.
Далее мы определям денотационный аналог подстановки аналогичным отношени-
ем in_denotational_sem_subst и показываем его свойства.
Наконец мы формализуем доказательства леммы 2 о свойстве замкнутости дено-
тационной семантики и леммы 1 об изменении денотационной семантики при замене
подставляемой свежей переменной.
28
Это определение позволяет нам в общем случае произвольных потоков доказать
принципиальные свойства поиска с чередованием, сформулированные ранее: мы дока-
зываем что поток-чередование конечен тогда и только тогда, когда конечны чередуе-
мые потоки, из чего следует лемма 6, и что элементами потока-чередования являются
в точности элементы чередуемых потоков, из чего следует лемма 4.
После этой предварительной работы мы можем переходить к формализации самой
операционной семантики. Она содержится в файле OperationalSem.v.
Прежде всего мы записываем индуктивные определения для нетерминальных со-
стояний nt_state и произвольных состояний state, а также для свойства согласо-
ванности нетерминальных состояний well_formed_nt_state.
Далее мы записываем нашу систему переходов в виде индуктивного отношения
естественным образом. При этом в каждый переход входит либо пометка-ответ, либо
явное обозначение непомеченного шага.
(* Labels *)
Inductive label : Set :=
| Step : label
| Answer : subst → nat → label.
(* Transitions *)
Inductive eval_step : nt_state → label → state → Set := ...
Мы устанавливаем её детерминированность, доказывая, что из любого нетерми-
нального состояния существует переход (Lemma eval_step_exists) и что этот пере-
ход (то есть комбинация из пометки на переходе и следующего состояния) уникален
(Lemma eval_step_unique). Кроме того, мы доказываем лемму 3 о сохранении согла-
сованности состояния при переходе.
После этого мы определяем саму операционную семантику как коиндуктивное от-
ношение op_sem между состоянием и потенциально бесконечным потоком, содержа-
щим пометки на пути и пропуски на месте непомеченных переходов.
Definition trace : Set := stream label.
CoInductive op_sem : state → trace → Set :=
| osStop : op_sem Stop Nil
| osNTState : ∀ nts l s t, eval_step nts l s →
op_sem s t →
op_sem ( NTState nts) ( Cons l t).
Мы также доказываем существование и уникальность (с коиндуктивно заданным
равенством) соответсвующего потока для любого состояния и формализуем определе-
ние денотационного аналога операционной семантики из раздела 3 (для него вводится
обозначение “{ | t , f |}”).
29
Наконец, мы формализуем доказательства лемм 4, 5 и 6 из раздела об операцион-
ной семантике.
Используя механизм экстракции кода из доказательств в Coq, мы извлекаем код
интерпретатора (функции, возвращающей поток ответов по начальному состоянию)
из доказательтва существования операционной семантики любого состояния. Этот ин-
терпретатор реализует определенную только что семантику по построению, а форма-
лизация доказательства корректности и полноты семантики, описанная далее, делает
его сертифицировано корректным (то есть дающим ответы, в точности отражающие
денотационную семантику).
Код на языке Haskell извлекается в файл extracted/interpreter.hs, а в соседнем
файле extracted/interpreter_wrapped.hs к этому коду дописываются несколько
простых примитивов для более удобного его использования (транслирующих обычные
натуральные числа и термы в наше представление и адекватно их отображающие), и
несколько стандартных примеров отношений и запросов на MiniKanren. Интерпрета-
тор демонстрирует ожидаемое поведение.
30
Финальные доказательства имеют относительно небольшой объем, однако значи-
тельная часть работы скрыта в доказательствах вспомогательных фактов о семанти-
ках в предыдущих файлах.
31
5. Прочие применения новой семантики
Помимо доказательства нашего основного результата — полноты поиска в языке
MiniKanren — определенная нами семантика может быть использована в качестве
инструмента для доказательства других полезных свойств исполнения программ в
языке. В данном разделе будут рассмотрены два примера таких применений. Резуль-
таты из данного раздела на данный момент не формализованы в Coq, однако они
не имеют принципиальной ценности сами по себе, в отличие от полноты поиска, и
используются нами только для демонстрации применимости семантики для доказа-
тельства различных свойств языка.
1. Jg1 ∨ g2 K = Jg2 ∨ g1 K
2. Jg1 ∧ g2 K = Jg2 ∧ g1 K
32
5.2. Опровергающая полнота отношений
Помимо доказательства общих свойств языка MiniKanren, мы можем использовать
нашу семантику для доказательства свойcтв конкретных программ. К ним относят-
ся некоторые важные свойства, описанные в литературе. Примером такого свойства
является опровергающая полнота (refutational completeness [5]) отношений.
Опровергающая полнота утверждает, что при вызовах данного отношения поиск
никогда не зацикливается, когда ответы заканчиваются. В более строгом виде встре-
чаются две различные формулировки: более слабая — любой вызов, не дающий отве-
тов, завершается — и более сильная — любой вызов, дающий конечное число ответов,
завершается. Операционная семантика для поиска с чередования позволяет форма-
лизовать обе эти формулировки.
33
Более достижимым свойством является ограниченная версия опровергающей пол-
ноты, при которой аргументам отношения при вызове не разрешается иметь общих
переменных. Мы будем называть это свойство линейной опровергающей полнотой.
34
Заключение
В рамках данной работы были получены следующие результаты.
35
Список литературы
[1] Baader Franz, Snyder Wayne. Handbook of Automated Reasoning / Ed. by
Alan Robinson, Andrei Voronkov. –– Amsterdam, The Netherlands, The Netherlands :
Elsevier Science Publishers B. V., 2001.
[3] Bertot Yves, Castéran Pierre. Interactive Theorem Proving and Program Development
- Coq’Art: The Calculus of Inductive Constructions. Texts in Theoretical Computer
Science. An EATCS Series. –– Springer, 2004.
[6] Byrd William E., Friedman Daniel P. αkanren: A Fresh Name in Nominal Logic
Programming // Proceedings of the 2007 Annual Workshop on Scheme and Functional
Programming. –– 2007. –– P. 79–90.
[7] Byrd William E., Holk Eric, Friedman Daniel P. miniKanren, Live and Untagged:
Quine Generation via Relational Interpreters (Programming Pearl) // Proceedings of
the 2012 Annual Workshop on Scheme and Functional Programming. –– Scheme ’12. ––
New York, NY, USA : ACM, 2012. –– P. 8–29.
[9] Debray Saumya K., Mishra Prateek. Denotational and operational semantics for
PROLOG // Formal Description of Programming Concepts - III: Proceedings of
the IFIP TC 2/WG 2.2 Working Conference on Formal Description of Programming
Concepts - III, Ebberup, Denmark, 25-28 August 1986. –– 1987. –– P. 245–274.
[10] Despeyroux Joëlle, Felty Amy P., Hirschowitz André. Higher-Order Abstract Syntax
in Coq // Typed Lambda Calculi and Applications, Second International Conference
on Typed Lambda Calculi and Applications, TLCA ’95, Edinburgh, UK, April 10-12,
1995, Proceedings. –– 1995. –– P. 124–138.
36
[11] Friedman Daniel P., Byrd William E., Kiselyov Oleg. The Reasoned Schemer. –– The
MIT Press, 2005.
[12] Hemann Jason, Friedman Daniel P. µKanren: A Minimal Functional Core for
Relational Programming // Proceedings of the 2013 Annual Workshop on Scheme
and Functional Programming. –– 2013.
[13] Jones Neil D., Mycroft Alan. Stepwise Development of Operational and Denotational
Semantics for Prolog // Proceedings of the 1984 International Symposium on Logic
Programming, Atlantic City, New Jersey, USA, February 6-9, 1984. –– 1984. –– P. 281–
288.
[15] Kothari Sunil, Caldwell James. A Machine Checked Model of Idempotent MGU
Axioms For Lists of Equational Constraints // Proceedings 24th International
Workshop on Unification, UNIF 2010, Edinburgh, United Kingdom, 14th July 2010. ––
2010. –– P. 24–38.
[16] Kriener Jael, King Andy. Semantics for Prolog with Cut - Revisited // Functional
and Logic Programming - 12th International Symposium, FLOPS 2014, Kanazawa,
Japan, June 4-6, 2014. Proceedings. –– 2014. –– P. 270–284.
[17] Kriener Jael, King Andy, Blazy Sandrine. Proofs you can believe in: proving
equivalences between Prolog semantics in Coq // 15th International Symposium
on Principles and Practice of Declarative Programming, PPDP ’13, Madrid, Spain,
September 16-18, 2013. –– 2013. –– P. 37–48.
[18] Kumar Ramana. Mechanising Aspects of miniKanren in HOL. –– Bachelor Thesis, The
Australian National University. –– 2010.
[20] Lozov Petr, Vyatkin Andrei, Boulytchev Dmitry. Typed Relational Conversion //
Proceedings of the International Symposium on Trends in Functional Programming. ––
2017.
[21] Near Joseph P., Byrd William E., Friedman Daniel P. alpha-leanTAP: A
Declarative Theorem Prover for First-Order Classical Logic // Logic Programming,
24th International Conference, ICLP 2008, Udine, Italy, December 9-13 2008,
Proceedings. –– 2008. –– P. 238–252.
37
[22] Paulson Lawrence C. Verifying the Unification Algorithm in LCF // Sci. Comput.
Program. –– 1985. –– Vol. 5, no. 2. –– P. 143–169.
[23] Pfenning F., Elliott C. Higher-order Abstract Syntax // SIGPLAN Not. –– 1988. ––
. –– Vol. 23, no. 7. –– P. 199–208.
[25] Ribeiro Rodrigo Geraldo, Camarão Carlos. A Mechanized Textbook Proof of a Type
Unification Algorithm // Formal Methods: Foundations and Applications - 18th
Brazilian Symposium, SBMF 2015, Belo Horizonte, Brazil, September 21-22, 2015,
Proceedings. –– 2015. –– P. 127–141.
38
A. Детальные доказательства приведенных
утверждений
В этом разделе будут приведены неочевидные детали для некоторых доказательств
из данной работы. При этом доказательства всех утверждений из данной работы,
кроме утверждений из раздела 5, верифицированы в Coq, и наиболее полные доказа-
тельства содержатся в формализации (см. раздел 4).
39
цели.
40
Для множества с этим свойством легко показать, что на пути из любого состояния
из этого множества нет помеченных переходов, при этом путь никогда не приходит в
терминальное состояние. Именно это и нужно, чтобы найти контрпример для опро-
вергающей полноты.
В качестве множества S возьмем множество согласованных состояний
41
соответствует опровергающей полноте, следует, что это же верно и для исход-
ного вызова: если число помеченых переходов для исходного вызова конечно, то
и число помеченных переходов для рекурсивного вызова кончено, а значит он
завершается, следовательно завершается и исходный (ведь вычисление второй
ветви дизъюнкции очевидно конечно).
42