32.7. Полиморфные обновления 373
нам снова нужен некий механизм, позволяющий более точную форму ограниченной квантификации; в
данном случае, проще всего добавить мезанизм для полиморфного обновления полей в записях.
2
Если
r является записью с полем x типа T, а t — терм типа T, то запись r x=t будет означать «запись,
совпадающая с r, за исключением поля x, значение которого равно t». Заметим, что такая операция
обновления вполне функциональна — она не изменяет r, а создает клонированную запись с другим
значением поля x.
С помощью такого примитива обновления записей можно примерно так написать функцию, отра-
жающую ожидаемое поведение тела метода inc:
f = λX <:{ a : Nat }. λx: X . r a = succ ( r . a);
Нужно, однако, соблюдать осторожность. Наивное правило типизации для операции обновления было
бы такое:
Γ r : R Γ R <: {l
j
:T
j
} Γ t :T
j
Γ r l
j
=t : R
Но это правило некорректно. Например, дупоустим, у нас есть
s = { x={ a =5 , b =6} , y= true };
Поскольку s : {x:{a:Nat,b:Nat},y:Bool}, и при этом {x:{a:Nat,b:Nat},y:Bool} <: {{a:Nat}}, вы-
шеприведенное правило позволило бы нам написать
s x ={ a =8} : {x :{ a: Nat ,b : Nat },y : Bool }
что было бы неверно, поскольку s x={a=8} редуцируется до {x={a=8},y=true}.
Проблема возникла из-за наследования в глубину для поля x, что позволило вывести
{x:{a:Nat,b:Nat},y:Bool} <: {x:{a:Nat}}. Наследование в глубину требуется запретить для полей,
которые могут быть обновлены. Этого можно добиться ценой простого расширения, позволяющего
метить поля особым знаком #.
Правила для таких «обновляемых записей» и для самой операции обновления приведены на
Рис. 32.1. Мы усложняем синтаксис типов записей, так что каждое поле оказывается снабжено меткой
изменчивости, указывающей, разрешено ли для этого поля наследование в глубину — метка # его
запрещает, а пустая строка позволяет (выбор пустой строки для этого варианта означает, что непоме-
ченные записи будут вести себя так же, как раньше). Правило наследования в глубину S-RcdDepth
уточняется и позволяет теперь наследование только для непомеченных полей. Наконец, мы добавляем
правило наследования S-RcdVariance, позволяющее изменять отметки полей с # на пустую строку —
иными словами, «забывать», что какое-то поле может обновляться. Правило типизации для операции
обновления требует, чтобы заменяемое поле было помечено знаком #. Правило E-Update реализует
операцию обновления.
Теперь функция f, обсуждавшаяся выше, пишется так:
f = λX <:{# a : Nat }. λr : X. r a = succ ( r .a );
f : X <{# a: Nat }. X -> X
и используется так:
r = {# a=0 , b= true };
f [{# a: Nat ,b: Bool }] r;
{# a=1 , b= true } : {#a : Nat , b: Bool }
Корректность операции обновления основывается на следующем наблюдении касательно уточнен-
ного отношения наследования:
Утверждение 32.7.1 Если R <: {#l:T
1
}, то R {...#l:R
1
. . .}, причем R
1
<: T
1
и T
1
<: R
1
.
Упражнение 32.7.2 Рекомендуется, : Соблюдается ли в этом исчислении свойство мини-
мальной типизации? Если да, докажите. Если нет, покажите, как исправить ситуацию.
2
Как всегда, существует несколько способов добиться похожего эффекта — вводя различные примитивы (некоторые из
них перечислены в разделе §32.10) или используя полиморфизм как в (Pierce and Turner 1994) — альтернатива более тяже-
ловесная с точки зрения нотации, но более элементарная теоретически. Тот вариант, который используется здесь, выбран
из-за своей простоты, а также потому, что он естественным образом подходит к примерам, которые сейчас последуют.
rev. 104