packages feed

liquidhaskell-0.8.10.7: benchmarks/sf/Induction.hs

{-@ LIQUID "--exact-data-con"                      @-}
{-@ LIQUID "--higherorder"                         @-}
{-@ LIQUID "--ple" @-}

module Induction where

import           Prelude (Char, Int, Bool(..))
import qualified Prelude

import Language.Haskell.Liquid.ProofCombinators

{-@ data Peano [toNat] @-} 
data Peano = O | S Peano

{-@ measure toNat @-}
{-@ toNat :: Peano -> Nat @-}
toNat :: Peano -> Int
toNat O     = 0
toNat (S n) = 1 Prelude.+ toNat n

{-@ reflect natPlus @-}
{-@ natPlus :: Peano -> Peano -> Peano @-}
natPlus :: Peano -> Peano -> Peano
natPlus O     n = n
natPlus (S m) n = S (natPlus m n)

{-@ reflect natMult @-}
{-@ natMult :: Peano -> Peano -> Peano @-}
natMult :: Peano -> Peano -> Peano
natMult n m = case n of
  O    -> O
  S n' -> natPlus m (natMult n' m)

{-@ theorem_plus_n_O :: n : Peano -> { n == natPlus n O } @-}
theorem_plus_n_O :: Peano -> Proof
theorem_plus_n_O O     = ( natPlus O O ) *** QED
theorem_plus_n_O (S n) = ( natPlus (S n) O
                         , theorem_plus_n_O n
                         ) *** QED

{-@ theorem_mult_0_r :: n : Peano -> { natMult n O = O } @-}
theorem_mult_0_r :: Peano -> Proof
theorem_mult_0_r O     = natMult O O *** QED
theorem_mult_0_r (S n) = ( natMult (S n) O
                         , theorem_mult_0_r n
                         , natPlus O O
                         ) *** QED

{-@ theorem_plus_n_Sm :: n : Peano -> m : Peano
      -> { S (natPlus n m) = natPlus n (S m) }
@-}
theorem_plus_n_Sm :: Peano -> Peano -> Proof
theorem_plus_n_Sm O     m = ( natPlus O m, natPlus O (S m) ) *** QED
theorem_plus_n_Sm (S n) m = ( natPlus (S n) m
                            , natPlus (S n) (S m)
                            , theorem_plus_n_Sm n m
                            ) *** QED

{-@ theorem_plus_comm :: n : Peano -> m : Peano
      -> { natPlus n m = natPlus m n }
@-}
theorem_plus_comm :: Peano -> Peano -> Proof
theorem_plus_comm O     m = ( natPlus O m, theorem_plus_n_O m ) *** QED
theorem_plus_comm (S n) m = ( natPlus (S n) m
                            , theorem_plus_comm n m
                            , theorem_plus_n_Sm m n
                            ) *** QED

{-@ theorem_plus_assoc :: n : Peano -> m : Peano -> p : Peano
      -> { natPlus n (natPlus m p) = (natPlus (natPlus n m) p) }
@-}
theorem_plus_assoc :: Peano -> Peano -> Peano -> Proof
theorem_plus_assoc O     m p = ( natPlus O (natPlus m p)
                               , natPlus O m
                               ) *** QED
theorem_plus_assoc (S n) m p = ( natPlus (S n) (natPlus m p)
                               , natPlus (S n) m
                               , natPlus (S (natPlus n m)) p
                               , theorem_plus_assoc n m p
                               ) *** QED

{-@ reflect double @-}
{-@ double :: Peano -> Peano @-}
double :: Peano -> Peano
double O     = O
double (S n) = S (S (double n))

{-@ theorem_double_plus :: n : Peano -> { double n = natPlus n n } @-}
theorem_double_plus :: Peano -> Proof
theorem_double_plus O     = ( double O, natPlus O O ) *** QED
theorem_double_plus (S n) = ( double (S n)
                            , theorem_double_plus n
                            , natPlus (S n) (S n)
                            , theorem_plus_n_Sm n n
                            ) *** QED

{-@ theorem_plus_swap :: n : Peano -> m : Peano -> p : Peano
      -> { natPlus n (natPlus m p) = natPlus m (natPlus n p) }
@-}
theorem_plus_swap :: Peano -> Peano -> Peano -> Proof
theorem_plus_swap n m p = ( theorem_plus_assoc n m p
                          , theorem_plus_comm n m
                          , theorem_plus_assoc m n p
                          ) *** QED

{-@ lemma_mult_distrib_S_n :: m : Peano -> n : Peano
      -> { natMult m (S n) = natPlus m (natMult m n) }
@-}
lemma_mult_distrib_S_n :: Peano -> Peano -> Proof
lemma_mult_distrib_S_n O     n = ( natMult O (S n)
                                 , natMult O n
                                 , natPlus O O
                                 ) *** QED
lemma_mult_distrib_S_n (S m) n = ( natMult (S m) (S n)
                                 , natPlus (S n) (natMult m (S n))
                                 , natPlus (S m) (natMult (S m) n)
                                 , natMult (S m) n
                                 , lemma_mult_distrib_S_n m n
                                 , theorem_plus_swap n m (natMult m n)
                                 ) *** QED

{-@ theorem_mult_comm :: m : Peano -> n : Peano
                      -> { natMult m n = natMult n m }
@-}
theorem_mult_comm :: Peano -> Peano -> Proof
theorem_mult_comm O     n = ( natMult O n
                            , theorem_mult_0_r n
                            ) *** QED
theorem_mult_comm (S m) n = ( natMult (S m) n
                            , theorem_mult_comm m n
                            , lemma_mult_distrib_S_n n m
                            ) *** QED