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