Kodutöö 12
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
?f ?x : (a->b) -> a ----------- -> b
Implikatsiooni sissetoomse (ehk {$\lambda$}-abstraktsiooni) reegli järgi saame järeldada implikatsiooni a->b
-- eeldusel, et saame näidata b
kui meile on antud a
.
(\ x => ?y) : a . . . b ------ -> a -> b
Reegli nime asemel kasutame vastavalt funktsioonirakendust või funktsiooni defineerimise süntaksit.
Kõik teised konstruktsioonid saame sisse tuua
data
abil loodud andmestruktuuridega, mille
kontruktoriteks on sissetoomise reeglid.
Esmalt on ülesandeks kontrollida, kas väljaviimise reeglid on Idrises tuletatavad.
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 tõestama uut teoreemi, nagu idVec
sõltuvat tüüpide loengus.)
Võrduse väljaviimiseks on rewrite .. in ..
reegel.
rewrite .. in .. : a = b -> P b ------------ -> P a
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 (abstraheerides P a
tüübist kõik a
esinemised) 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) = let re = plusNull k in -- S (plus k 0) = S k myrewrite (\ z => S z = S k) re -- rewrite re in -- S k = S k 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