Нормализация путем оценки
В языков программирования семантике нормализация путем оценки (NBE) — это метод получения нормальной формы термов λ-исчисления путем обращения к их денотационной семантике . Термин сначала интерпретируется в денотационную модель структуры λ-терма, а затем канонический (β-нормальный и η-длинный) представитель извлекается путем материализации обозначения. Такой по существу семантический подход без сокращений отличается от более традиционного синтаксического, основанного на сокращении описания нормализации как сокращения в системе переписывания терминов , где β-сокращения разрешены глубоко внутри λ-терминов.
NBE впервые был описан для просто типизированного лямбда-исчисления . [1] С тех пор он был распространен как на более слабые системы типов , такие как нетипизированное лямбда-исчисление. [2] с использованием теоретико-предметного подхода, а также к более богатым системам типов, таким как несколько вариантов теории типов Мартина-Лёфа . [3] [4] [5] [6]
Контур
[ редактировать ]Рассмотрим просто типизированное лямбда-исчисление , где типы τ могут быть базовыми типами (α), типами функций (→) или продуктами (×), заданными следующей грамматикой формы Бэкуса – Наура (→ сопоставление справа, как обычно):
- (Типы) τ ::= a | τ 1 → τ 2 | т 1 × т 2
Они могут быть реализованы как тип данных на метаязыке; например, для Standard ML мы можем использовать:
datatype ty = Basic of string
| Arrow of ty * ty
| Prod of ty * ty
Термины определяются на двух уровнях. [7] Нижний синтаксический уровень (иногда называемый динамическим уровнем) — это представление, которое предполагается нормализовать.
- (Синтаксические термины) s , t ,… ::= var x | лам ( Икс , т ) | приложение ( с , т ) | пара ( s , т ) | фст т | снд т
Здесь lam / app (соответственно пара / fst , snd ) — это формы intro / elim для → (соответственно ×), а x — переменные . Эти термины предназначены для реализации как тип данных первого порядка в метаязыке:
datatype tm = var of string
| lam of string * tm | app of tm * tm
| pair of tm * tm | fst of tm | snd of tm
Денотационная семантика (закрытых) терминов метаязыка интерпретирует конструкции синтаксиса с точки зрения особенностей метаязыка; таким образом, lam интерпретируется как абстракция, app как приложение и т. д. Конструируются следующие семантические объекты:
- (Семантические термины) S , T ,… ::= LAM (λ x . S x ) | ПАРА ( S , Т ) | СИН т
Обратите внимание, что в семантике нет переменных или форм исключения; они представлены просто как синтаксис. Эти семантические объекты представлены следующим типом данных:
datatype sem = LAM of (sem -> sem)
| PAIR of sem * sem
| SYN of tm
Существует пара функций с индексацией типов, которые перемещаются между синтаксическим и семантическим уровнем. Первая функция, обычно обозначаемая ↑ τ , отражает синтаксис термина в семантике, а вторая воплощает семантику как синтаксический термин (записанный как ↓ т ). Их определения взаимно рекурсивны следующим образом:
Эти определения легко реализуются на метаязыке:
(* fresh_var : unit -> string *)
val variable_ctr = ref ~1
fun fresh_var () =
(variable_ctr := 1 + !variable_ctr;
"v" ^ Int.toString (!variable_ctr))
(* reflect : ty -> tm -> sem *)
fun reflect (Arrow (a, b)) t =
LAM (fn S => reflect b (app (t, (reify a S))))
| reflect (Prod (a, b)) t =
PAIR (reflect a (fst t), reflect b (snd t))
| reflect (Basic _) t =
SYN t
(* reify : ty -> sem -> tm *)
and reify (Arrow (a, b)) (LAM S) =
let val x = fresh_var () in
lam (x, reify b (S (reflect a (var x))))
end
| reify (Prod (a, b)) (PAIR (S, T)) =
pair (reify a S, reify b T)
| reify (Basic _) (SYN t) = t
Индукцией типа по структуре типов следует, что если семантический объект S обозначает корректно типизированный терм s τ, то овеществление объекта (т. е. ↓ т S) создает β-нормальную η-длинную форму s . Следовательно, остается только построить исходную семантическую интерпретацию S из синтаксического термина s . Эта операция, записанная ∥ s ∥ Γ , где Γ — контекст привязок, выполняется путем индукции исключительно по временной структуре:
В реализации:
datatype ctx = empty
| add of ctx * (string * sem)
(* lookup : ctx -> string -> sem *)
fun lookup (add (remdr, (y, value))) x =
if x = y then value else lookup remdr x
(* meaning : ctx -> tm -> sem *)
fun meaning G t =
case t of
var x => lookup G x
| lam (x, s) => LAM (fn S => meaning (add (G, (x, S))) s)
| app (s, t) => (case meaning G s of
LAM S => S (meaning G t))
| pair (s, t) => PAIR (meaning G s, meaning G t)
| fst s => (case meaning G s of
PAIR (S, T) => S)
| snd t => (case meaning G t of
PAIR (S, T) => T)
Обратите внимание, что существует множество неисчерпывающих случаев; однако, если применить его к закрытому, правильно типизированному термину, ни один из этих пропущенных случаев никогда не встречается. Тогда операция НБЕ на закрытых условиях будет выглядеть следующим образом:
(* nbe : ty -> tm -> tm *)
fun nbe a t = reify a (meaning empty t)
В качестве примера его употребления рассмотрим синтаксический термин SKK
определено ниже:
val K = lam ("x", lam ("y", var "x"))
val S = lam ("x", lam ("y", lam ("z", app (app (var "x", var "z"), app (var "y", var "z")))))
val SKK = app (app (S, K), K)
Это хорошо известное кодирование функции тождества в комбинаторной логике . Нормализация его по типу идентификатора дает:
- nbe (Arrow (Basic "a", Basic "a")) SKK;
val it = lam ("v0",var "v0") : tm
На самом деле результат имеет η-длинную форму, как можно легко увидеть, нормализовав его к другому типу идентификатора:
- nbe (Arrow (Arrow (Basic "a", Basic "b"), Arrow (Basic "a", Basic "b"))) SKK;
val it = lam ("v1",lam ("v2",app (var "v1",var "v2"))) : tm
Варианты
[ редактировать ]Использование уровней де Брейна вместо имен в остаточном синтаксисе делает reify
чистая функция, в которой нет необходимости fresh_var
. [8]
Тип данных остаточных термов также может быть типом данных остаточных термов в нормальной форме .
Тип reify
(и, следовательно, из nbe
) тогда дает понять, что результат нормализован.
А если тип данных нормальных форм типизирован, то тип reify
(и, следовательно, из nbe
) затем дает понять, что нормализация сохраняет тип. [9]
Нормализация путем оценки также масштабируется до просто типизированного лямбда-исчисления с суммами ( +
), [7] используя операторы управления с разделителями shift
и reset
. [10]
См. также
[ редактировать ]- MINLOG — помощник по проверке , использующий NBE в качестве механизма перезаписи.
Ссылки
[ редактировать ]- ^ Бергер, Ульрих; Швихтенберг, Хельмут (1991). «Обратный функционал оценки для типизированного λ-исчисления». ЛИКС .
- ^ Филинский, Анджей; Роде, Хеннинг Корсхольм (2005). «Денотационное описание нетипизированной нормализации путем оценки» . Основы программного обеспечения и вычислительных структур (FOSSACS) . Том. 10. дои : 10.7146/brics.v12i4.21870 .
- ^ Коканд, Тьерри; Дюбьер, Питер (1997). «Интуиционистские конструкции моделей и доказательства нормализации». Математическая структура в информатике . 7 (1): 75–94. дои : 10.1017/S0960129596002150 .
- ^ Абель, Андреас; Элиг, Клаус; Дюбьер, Питер (2007). «Нормализация путем оценки теории типов Мартина-Лёфа с одной вселенной» (PDF) . МФПС .
- ^ Абель, Андреас; Коканд, Тьерри; Дюбьер, Питер (2007). «Нормализация путем оценки теории типов Мартина-Лёфа с типизированными суждениями о равенстве» (PDF) . ЛИКС .
- ^ Гратцер, Дэниел; Стерлинг, Джон; Биркедал, Ларс (2019). «Реализация теории модально-зависимых типов» (PDF) . ИКФП .
- ^ Перейти обратно: а б Дэнви, Оливье (1996). «Частичная оценка, ориентированная на тип» ( gzip PostScript ) . ПОПЛ : 242–257.
- ^ Филинский, Анджей. «Семантический отчет о частичной оценке, направленной на тип» . Принципы и практика декларативного программирования . дои : 10.7146/brics.v6i17.20074 .
- ^ Дэнви, Оливье; Ригер, Мортен; Роуз, Кристоффер (2001). «Нормализация путем оценки с типизированным абстрактным синтаксисом» . Журнал функционального программирования . 11 (6): 673–680. дои : 10.1017/S0956796801004166 .
- ^ Дэнви, Оливье; Филинский, Анджей (1990). «Абстрагирующий контроль». LISP и функциональное программирование . стр. 151–160. дои : 10.1145/91556.91622 . ISBN 0-89791-368-Х . S2CID 6426191 .