Свойства списков:
- каждый элемент может встретиться несколько раз
- порядок определен (и существенен)
type
LT1 = T1-list
NLT1 = T1-inflist
<.1,2,3.>
<..>
списочное выражение (rangered list expression)
<.3...7> = <.3,4,5,6,7.>
<.3..3.> = <.3.>
<.3..2.> = <..>
генерация списка на основе имеющегося
<. 2*n | n in <.1..100.> :- true .>
<. 2*n | n in <.1..100.> .>
<.n | n in <.1..100.> :- is_a_prime(n).> = ...
value
INTLIST : (Int >< Int)-list = <. (1,2), (2,2), (2,1), (3,1).>
.....
....... <. (x,f(y)) | (x,y) in INTLIST :- x>y .>
^ : T-list >< T-list -> T-list concatenation
in : T >< T-list
len : T-list -> Nat
hd : T-list -~-> T
tl : T-list -~-> T-list
inds : T-list -> Nat-set
elems : T-list -> T-set
n Диаграмма Гогена
|
inds fl = {1..len fl} - для конечных списков
inds il = {idx | idx : Nat :- idx >= 1} - для бесконечных cписков
elems l = {l(idx) | idx : Nat :- idx isin inds l}
"abc" = <.'a','b','c'.>
"" = <..>
QUEUE =
class
type
Element,
Queue = Element-list
value
empty : Queue,
put : Element >< Queue -> Queue,
get : Queue -~-> Queue >< Element
axiom forall e : Element, q : Queue
empty is <..>,
put (e,q) is q ^ <.e.>,
get(q) is (tl q, hd q)
pre q ~= empty
end
(Объяснить, что forall – это сокращенная запись, инструментом не поддерживается)
Следующий пример показывает, как строятся иерархии классов с расширениями (extend).
Вторая цель примера – показать “хороший стиль”. Здесь мы не будем описывать алгоритмы. Мы описываем только свойства результата.
LIST_PROPERTIES =
class
value
is_permutation : Int-list >< Int-list -> Bool,
is_sorted : Int-list -> Bool
axiom forall l,l1,l2 ; Int-list :-
is_permutation(l1,l2) is
(all i : Int :-
card {idx | idx : Nat :- idx isin l1 /\ l1(idx) = i} =
card {idx | idx : Nat :- idx isin l2 /\ l2(idx) = i},
is_sorted(l) is
(all idx1,idx2 : Nat :-
{idx1,idx2} <<= inds l /\ idx1 < idx2 =>
l(idx1) <= l(idx2))
end
Ниже приведено расширение рассмотренного выше модуля
SORTING =
extend LIST_PROPERTIES with
class
value
sort : Int-list -> Int-list
axiom forall l : Int-list :-
sort(l) as l1 post is_permutation(l1,l2) /\ is_sorted(l1)
end
Более сложный пример. Цель примера: сравнить впоследствие спецификации Database в термина сорт-типов, множеств кортежей и списков записей.
KEY =
class
type
Key
value
less_than : Key >< Key -> Bool
axiom forall k,k1,k2,k3 : Key :-
[anti_reflexive]
~less_than(k,k),
[transitive]
less_than(k1,k2) /\ less_than(k2,k3) => less_than(k1,k3),
[total_order]
less_than(k1,k2) \/ less_than(k2,k1) \/ k1=k2
end
DATA =
class
type
Data
value
not_found : Data
end
RECORD =
extend KEY with extend DATA with
class
type
Record = Key >< Data
value
new_record : Key >< Data -> Record,
key_of : Record -> Key,
data_of : Record -> Data
axiom forall k : Key, d : Data :-
new_record(k,d) is (k,d),
key_of(k,d) is k,
data_of(k,d) is d
end
LIST_DATABASE =
extend RECORD with
class
type
Database = {| rl : record-list :- is_wf_Database(rl) |}
value
is_wf_Database : Record-list -> Bool,
empty : Database,
insert : Key >< Data >< Database -> Database,
remove : Key >< Database -> Database,
defined : Key >< Database -> Bool,
lookup : Key >< Database -> Data
axiom forall k : Key, d : Data, rl : record-list db : Database :-
is_wf_Database(rl) is
(all r1,r2 : Record, left,right : Record-list :-
rl = left ^ <.r1,r2.> ^ right =>
less_than(key_of(r1),key_of(r2))),
empty is <..>,
insert(k,d,db) as db1
post elems db1 = (elems remove(k,db)) union {new_record(k,d)},
remove(k,db) is <.r | r in db :- key_of(r) ~= k.>,
defined(k,db) is
if db = <..> \/ less_than(k,key_of(hd db)) then false
else key_of(hd db) = k \/ defined(k,tl db)
end,
lookup(k,db) is
if db = <..> \/ less_than(k,key_of(hd db)) then not_found
elsif key_of(hd db) = k then data_of(hd db) then data_of(hd db)
else lookup(k, tl db)
end
end
n Свойства отображений:
- каждый ключ может встретиться только один раз
- порядок ключей не определен
type
MT12 = T1 -m-> T2
[1 +> true, 3+>false, 2+>true]
[]
[“Petrov”+>”912-5317”, “Ivanov”+>”125-7652”
генерация отображения
[ n+>2*n | n : Nat :- n < 100 ]
dom
rng
m(k) - “применение” - найти значение по ключу k в отображении m
!! (†) - (dagger) добавить или переопределить значение ключа (override)
union - добавить (но не переопределить)
# (°) - композиция
\ - убрать ключи из s
/ - оставить только ключи из s
m \ s = [d +> m(d) | d : T1 :- d isin dom m /\ d ~isin s] /* restricted by */m / s = [d +> m(d) | d : T1 :- d isin dom m /\ d isin s] /* restricted to */
n Диаграмма Гогена
|
Пример с использованием MAP
LIBRARY_MAP =
class
type
Books = Book-set,
Log = Book -m-> Reader,
Readers = Reader-set,
Reader, Book
value
book_out : Reader >< Readers >< Book >< Books>< Log-~-> Log
........book_in : Book >< Books >< Log -~-> Log,
register : Reader >< Readers -~-> Readers
register : Book >< Books -~-> Books
......
end