Kodutöö 10
Tõestused Idris2-s. NB! Koodi sees on mitmed väikesed ülesanded.
Lausearvutus
Idris-e loogika aluseks on keelde sisse ehitatud implikatsion (ehk funktsioonitüüp).
Implikatsiooni väljaviimise (ehk funktsiooni rakenduse) reegel võtab implikatsiooni a->b
ja eelduse a
ning annab välja b
app : (a->b) -> a ----------- -> b
Implikatsiooni sissetoomse (ehk {$\lambda$}-abstraktsiooni) reegel võtab implikatsiooni a->b
ja eelduse a
ning annab välja b
(\ x => y) : a --- -> b
Need reeglid on sisse ehitatud -- definitsioone me anda ei saa (ja ei pea).
Kõik teised konstruktsioonid saame sisse tuua
data
abil loodud andmestruktuuridega.
Kontruktoriteks on sissetoomise reeglid.
Konjunktsioon
-- ainult täielikud funktsioonid tagavad turvalisuse %default total infixl 10 /\ data (/\) : Type -> Type -> Type where ConI : a -> b ------ -> a /\ b -- Väljaviimise reegleid ise defineerima ei pea aga saame nende paikapidavust kontrollida. conEl : a /\ b ------ -> a -- Reegel kehtib, kui saame anda definitsiooni. conEl = ?conEl_v conEr : a /\ b ------ -> b conEr = ?conEr_v
Disjunktsioon
infixl 11 \/ data (\/) : Type -> Type -> Type where DisjIl : a ------ -> a \/ b DisjIr : b ------ -> a \/ b disjE : (a\/b) -> (a -> c) -> (b -> c) ---------------------------------- -> c disjE x f g = ?disjE_v
Eitus ja väärus
%hide Not -- juba std. teegis olemas data Not : Type -> Type where NotI : (a -> Void) ----------- -> Not a NotE : Not a -> a ---------- -> Void NotE x = ?NotE_v --data Void : Type where ---- meelega jäetud tühjaks VoidE : Void ---- -> b VoidE q impossible
Lausearvutuse ülesanne ex1
ex1 : a /\ (b -> c) /\ (a -> b) ------------------------- -> c ex1 = ?ex1_v
Kalmeri lemmikväide:
Klassikalises loogikas kehtib kummaliselt kõlav väide: a "põhjustab" b-d või b "põhjustab" a-d -- iga a ja b korral. (Näiteks a:="Täna on reede", b:="vihma sajab".)
--(Vihje: kasuta lambdat) ex2 : a \/ Not a -------------------- -> (a -> b) \/ (b -> a) ex2 a = ?ex2_v
Paaris
Mingi oma teooria lisamiseks tuleb defineerida data
vastavate aksioomidega.
Näiteks teooria paarisarvudest.
data Even : Nat -> Type where Even_Zero : -------- Even 0 Even_Succ : Even n ------------ -> Even (2+n) even4 : Even 4 even4 = ?even4_v even8 : Even 8 even8 = ?even8_v plusEvenEven : Even n -> Even m ------------------ -> Even (n+m) plusEvenEven a b = ?plusEvenEven_v multEvenEven : Even n -> Even m ------------------ -> Even (n*m) multEvenEven a b = ?multEvenEven_v
Paaris/Paaritu
data Odd : Nat -> Type where Odd_one : -------- Odd 1 Odd_Succ : Odd n ----------- -> Odd (2+n) odd7 : Odd 7 odd7 = ?odd7_v evenOdd : Even n ---------- -> Odd (1+n) evenOdd e = ?evenOdd_v plusOddOdd : Odd n -> Odd m ------------------- -> Even (n+m) plusOddOdd a b = ?plusOddOdd_v plusEvenOdd : Even n -> Odd m ------------------- -> Odd (n+m) plusEvenOdd a b = ?plusEvenOdd_v plusNullOdd : Odd m ------------ -> Odd (m+0) plusNullOdd a = ?plusNullOdd_v
Võrdused ja rewrite
Võrduste teooria on standardteegis defineeritud põhimõtteliselt nii:
data (=) : Type -> Type -> Type where Refl : {a:Type} ---------- -> a = a
Nii saame defineerida üldisi võrdusi ja ei pea enam iga kasutuse jaoks uut teoreemi (nagu idVec
loengust) tõestama.
Võrduse väljaviimiseks on rewrite .. in ..
reegel.
rewrite .. in .. : a=b -> Pb ---------- -> Pa
S.t. kui meil on vaja tõestada S (n+0) = S n
ja me teame võrdust eq: n+0 = n
siis rewrite eq
asendab eesmärgis n+0
-d n
-dega. Jääb tõestada S n = S n
.
Muide, rewrite
-i saab ka ise implementeerida, aga seda on ebamugavam kasutada. Idrise sisseehitatud rewrite
suudab P
ise tuletada aga myrewrite
puhul on vaja see argumendiks anda.
myrewrite : (p:a -> Type) -> {x:a} -> {y:a} -> x=y -> p y -> p x myrewrite p Refl h = h
Näidis
Proovi ka ise seda lahendada, et aru saada, kuidas rewrite töötab.
plusNull : (n:Nat) --------- -> n+0 = n plusNull 0 = Refl plusNull (S k) = rewrite plusNull k in Refl
Ülesanne: liitmise assotsiatiivsus
Kasuta rewrite-i.
plusAssoc : (m:Nat) -> (n:Nat) -> (q:Nat) ------------------------------ -> m + (n + q) = (m + n) + q plusAssoc m n q = ?plusAssoc_v
Tärnülesanne: multOddOdd
-- Vihjed: case-split a ja b (tuleb kolm juhtu) -- Esimene juht on triviaalne, teised vajavad natuke vaeva. -- -- Märkus: Idrise poolt genereeritud 2+n asemel tuleb -- käsitsi panna S (S n) selleks, et muutuja n oleks kättesaadav. multOddOdd : (n:Nat) -> (m:Nat) -> Odd n -> Odd m ------------------------------------------- -> Odd (n*m) multOddOdd n m a b = ?multOddOdd_v