Задача 5 Дать эквивалентное определение без
использований вариантных определений
Начнем с простенького примера с коллоквиума прошлого года:
type Collection
empty | add (Collection <-> head, tail:Collection) [Знак <-> обозначает реконструктор. То есть то, что мы можем по
созданной функцией add коллекции реконструировать
(заменять) значение указанного аргумента. Выражение типа tail:
Collection
обозначает возможность однозначного конструирования этого "хвоста" из
коллекции полученной функцией add, сиречь конструктор]
type Collection
value
empty : Collection,
add: Collection >< Collection
-> Collection
head : Collection >< Collection -~-> Collection,
tail : Collection -~-> Collection
axiom
[disjoint
- собственно, то, что конструироемое функцией add или head ни в
коем случае не
равно empty]
all c1, c2: Collection:-
empty ~= add(c1, c2)/\ empty ~= head(c1, c2)
[induction - читать как: для любого предиката над
типом коллекция, если справедлив предикат над пустой коллекцией, и если для
любых двух коллекций из справедливости предиката для них следуют справедливость
предиката для add и head,
то следует справедливость предиката для любой коллекции; по-моему
разумеию мы формулируем свойство коллекции оставаться
коллекцией при выполнении указанных функций]
all IsC: Collection
-> Bool :-
IsC(empty) /\ (all
c1, c2: Collection:- (IsC(c1) /\ IsC(c2)) => IsC(add(c1,
c2)) /\ IsC(head(c1,
c2))) => (all c: Collection :- IsC(c)),
[вот аксиома выражающая вышесказанное о реконструкторе]
all c1, c2, c3 : Collection :-
head (c1, add(c2, c3)) is add(c1, c3)
[вот аксиома выражающая вышесказанное об
однозначном конструировании]
all c1, c2: Collection:- tail
(add(c1,c2)) is c2
Пример, разобранный в варианте:
type Elem,
Collection
empty |
add(Collection <-> head, first: Elem, Elem <-> new_second)
type Elem,
Collection
value empty: Collection,
add:
Collection >< Elem >< Elem
-> Collection,
head: Collection >< Collection -~-> Collection,
first: Collection -~-> Elem,
new_second: Elem ><
Collection -~-> Collection
axiom
[disjoint - аналогично]
all c, c1: Collection, e1, e2: Elem :-
empty ~= add(c, e1, e2) /\ empty ~= head(c, c1) /\ empty ~= new_second(e1,
c)
[induction и тут
точно так же]
all IsC:
Collection -> Bool :-
IsC(empty)
/\ (all c1, c2: Collection, e1, e2: Elem :- ( (IsC(c1)
/\ IsC(c2))
=> IsC(add(c1,
e1, e2)) /\ IsC(head(c1,
c2)) /\ IsC(new_second(e1, c1)) ) => (all c: Collection :- IsC(c))
[head_add - указываем реконструироемость]
all c1, c2: Collection, e1, e2: Elem :-
head(c1, add(c2, e1, e2)) is add(c1, e1, e2)
[first_add - тоже
самое]
all c: Collection, e1, e2: Elem :-
first(add(c, e1, e2)) is e1
[new_second_add - и тут тоже]
all c: Collection, e1, e2, e3: Elem :-
new_second(e1, add(c, e2, e3)) is add(c, e2, e1)
Еще пример из вариантов:
[вот тут небольшая заковыка - имя head
указано трижды. Не бойтесь - это всего лишь
перегруженная функция).
type Elem,
Collection
empty
| add1(head: Elem) |
add2( Elem <-> head)
type
Elem, Collection
value
empty: Collection
add1: Elem -> Collection
add2: Elem -> Collection
head: Elem >< Collection -~-> Collection
head: Collection -~-> Element
axiom
[disjoint
- аналогично]
all c: Collection, e1, e2, e3: Elem :-
empty ~= add1(e1) /\ empty ~= add2(e2) /\ empty ~= head(e3, c)
[induction и тут
точно так же]
all IsC:
Collection -> Bool :-
IsC(empty)
/\ (all c: Collection, e1, e2, e3: Elem :- ( IsC(c)
=> IsC(add1(e1)
/\ IsC(add2(e2))
/\ IsC(head(e3,
c)) ) => (all c: Collection :- IsC(c))
[head_add1 - указываем конструироемость]
all e1, e2: Elem:- head(add1(e1)) is e1,
[head_add2 - указываем конструироемость и
реконструироемость одновременно :)
- ффтыкайте]
all c1, c2: Collection, e1, e2: Elem
head( head (e1, add(e2))) is e2
[ для тех
кому непонятно, распишу в
две аксиомы: реконструироемость all c1: Collection, e: Elem:- head(e1, add(e2)) is add(e1)
и конструироемость all e: Elem
head (add(e)) is e ]