packages feed

liquidhaskell-0.7.0.0: tests/pos/sf/Basics.hs

{-@ LIQUID "--exact-data-con"                      @-}
{-@ LIQUID "--higherorder"                         @-}
{-@ LIQUID "--totality"                            @-}
{-@ LIQUID "--automatic-instances=liquidinstances" @-}

{- NOTE:

   1. See the TODO:trivial for cases where the instances seems to fail

   2. Would be nice to have case-splitting combinatores,
      e.g. for thmAndbCom,  thmAndbExch which are super boilerplate-y

   3. For @minsheng: See the rewritten signature for `thmEqBeq`;
      we don't really need `rewrite` as the SMT
      does "congruence closure" automatically.

 -}

module Basics where

  -- (
    -- -- * Booleans
    -- Bool(..)
  -- , negb, andb, orb
--
    -- -- * Peano numerals
  -- , Peano(..), toNat
  -- , plus, mult
  -- , beq, ble, blt
  -- )
  -- where

import           Prelude (Char, Int)
import qualified Prelude
import           Language.Haskell.Liquid.ProofCombinators

{-@ reflect incr @-}
incr :: Int -> Int
incr x = x Prelude.+ 1

--------------------------------------------------------------------------------
-- | Days ----------------------------------------------------------------------
--------------------------------------------------------------------------------

-- NOTE: clunky to have to redefine this ...

{-@ data Day = Monday
             | Tuesday
             | Wednesday
             | Thursday
             | Friday
             | Saturday
             | Sunday
  @-}

data Day = Monday
         | Tuesday
         | Wednesday
         | Thursday
         | Friday
         | Saturday
         | Sunday

{-@ reflect nextWeekDay @-}
nextWeekDay :: Day -> Day
nextWeekDay Monday    = Tuesday
nextWeekDay Tuesday   = Wednesday
nextWeekDay Wednesday = Thursday
nextWeekDay Thursday  = Friday
nextWeekDay Friday    = Monday
nextWeekDay Saturday  = Monday
nextWeekDay Sunday    = Monday


{-@ testNextWeekDay :: { nextWeekDay (nextWeekDay Saturday) == Tuesday } @-}
testNextWeekDay
  = trivial
-- = nextWeekDay (nextWeekDay Saturday) ==. Tuesday *** QED



--------------------------------------------------------------------------------
-- | Booleans ------------------------------------------------------------------
--------------------------------------------------------------------------------

{-@ data Bool = True | False @-}
data Bool = True | False

{-@ reflect negb @-}
negb :: Bool -> Bool
negb True  = False
negb False = True

{-@ reflect orb @-}
orb :: Bool -> Bool -> Bool
orb False False = False
orb _     _     = True

{-@ testOr1 :: { orb True True == True } @-}
testOr1 = trivial -- orb True True *** QED

{-@ testOr2 :: { orb True False == True } @-}
testOr2 = trivial -- orb True False *** QED

{-@ testOr3 :: { orb False True == True } @-}
testOr3 = trivial -- orb False True *** QED

{-@ testOr4 :: { orb False False == False } @-}
testOr4 = trivial -- orb False False *** QED

{-@ reflect andb @-}
andb :: Bool -> Bool -> Bool
andb True True = True
andb _    _    = False

{-@ andbCom :: a:_ -> b:_ -> { andb a b = andb b a } @-}
andbCom :: Bool -> Bool -> Proof
andbCom a b = trivial

-- Exercise 1 ------------------------------------------------------------------

{-@ reflect nandb @-}
nandb :: Bool -> Bool -> Bool
nandb a b = negb (andb a b)

{-@ testNand1 :: { nandb True True == False }  @-}
testNand1 = trivial

{-@ testNand2 :: { nandb True False == True }  @-}
testNand2 = trivial

{-@ testNand3 :: { nandb False True == True }  @-}
testNand3 = trivial

{-@ testNand4 :: { nandb False False == True } @-}
testNand4 = trivial

-- Exercise 2 ------------------------------------------------------------------

{-@ reflect andb3 @-}
andb3 :: Bool -> Bool -> Bool -> Bool
andb3 a b c = andb (andb a b) c

{-@ testAnd31 :: { andb3 True True True == True }  @-}
testAnd31 = trivial

{-@ testAnd32 :: { andb3 False True True == False }  @-}
testAnd32 = trivial

{-@ testAnd33 :: { andb3 True False True == False }  @-}
testAnd33 = trivial

{-@ testAnd34 :: { andb3 True True False == False }  @-}
testAnd34 = trivial

--------------------------------------------------------------------------------
-- | Peano ---------------------------------------------------------------------
--------------------------------------------------------------------------------

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

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

{-@ reflect even @-}
even :: Peano -> Bool
even O         = True
even (S O)     = False
even (S (S n)) = even n

{-@ test_Even0 :: { even O == True } @-}
test_Even0 :: Proof
test_Even0 = trivial

-- LH ISSUE #995
{-@ test_Even4 :: { even (S (S (S (S O)))) == True } @-}
test_Even4 :: Proof
test_Even4
  =   even (S (S (S (S O))))
  ==. even (S (S O))
  ==. even O
  ==. True
  *** QED

{-@ test_Even5 :: { even (S (S (S (S (S O))))) = False } @-}
test_Even5 :: Proof
test_Even5
  =   even (S (S (S (S (S O)))))
  ==. even (((S (S (S O)))))
  ==. even (((((S O)))))
  ==. False
  *** QED

-- | Plus & Mult ---------------------------------------------------------------

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

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

{- TODO:trivial testPlus1 :: { plus (S (S O)) O == (S (S O)) } @-}
testPlus1 = trivial

{- TODO:trivial testMult1 :: { mult (S (S O)) (S (S O)) == (S (S (S (S O)))) } @-}
testMult1 = trivial

-- | Factorial -----------------------------------------------------------------

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

{- TODO:trivial testFactorial1 :: { factorial (S (S (S O)))  == S (S (S (S (S (S O))))) } @-}
testFactorial1 = trivial

-- | Peano Comparisons ---------------------------------------------------------

{-@ reflect beq @-}
beq :: Peano -> Peano -> Bool
beq O     O     = True
beq (S m) (S n) = beq m n
beq _     _     = False

{-@ reflect ble @-}
ble :: Peano -> Peano -> Bool
ble O     _     = True
ble (S m) O     = False
ble (S m) (S n) = ble m n

{-@ testBle1 :: { ble (S (S O)) (S (S O))  == True } @-} -- TODO:trivial
testBle1
  =   ble (S (S O)) (S (S O))
  ==. ble ((S O)) ((S O))
  ==. ble O O
  *** QED

{-@ testBle2 :: { ble (S (S O)) (S (S (S O)))  == True } @-} -- TODO:trivial
testBle2
  =   ble (S (S O)) (S (S (S O)))
  ==. ble (S O) (S (S O))
  ==. ble O (S O)
  *** QED

{-@ testBle3 :: { ble  (S (S (S O))) (S (S O)) == False } @-} -- TODO:trivial
testBle3
  =   ble (S (S (S O))) (S (S O))
  ==. ble (S (S O)) (S O)
  ==. ble (S O) O
  *** QED

-- | Exercise blt --------------------------------------------------------------

{-@ reflect blt @-}
blt :: Peano -> Peano -> Bool
blt O     O     = False
blt O     (S n) = True
blt (S m) O     = False
blt (S m) (S n) = blt m n

{-@ testBlt1 :: { blt (S (S O)) (S (S O))  == False } @-} -- TODO:trivial
testBlt1
  =   blt (S (S O)) (S (S O))
  ==. blt ((S O)) ((S O))
  ==. blt O O
  *** QED

{-@ testBlt2 :: { ble (S (S O)) (S (S (S O)))  == True } @-} -- TODO:trivial
testBlt2
  =   ble (S (S O)) (S (S (S O)))
  ==. ble (S O) (S (S O))
  ==. ble O (S O)
  *** QED

{-@ testBlt3 :: { ble  (S (S (S O))) (S (S O)) == False } @-} -- TODO:trivial
testBlt3
  =   ble (S (S (S O))) (S (S O))
  ==. ble (S (S O)) (S O)
  ==. ble (S O) O
  *** QED

-- | Proof by Simplification ---------------------------------------------------

{-@ thmPlus_O_l :: n:Peano -> { plus O n == n } @-}
thmPlus_O_l :: Peano -> Proof
thmPlus_O_l n = trivial

{-@ thmPlus_1_N :: n:Peano -> { plus (S O) n = S n } @-}
thmPlus_1_N :: Peano -> Proof
thmPlus_1_N n = trivial

{-@ thmMult_0_l :: n:Peano -> { mult O n = O } @-}
thmMult_0_l :: Peano -> Proof
thmMult_0_l n = trivial

-- | Proof by Simplification ---------------------------------------------------

{-@ thmPlusId :: a:Peano -> b:Peano -> { a = b => plus a a = plus b b } @-}
thmPlusId :: Peano -> Peano -> Proof
thmPlusId a b = trivial

{-@ thmPlusId' :: n:Peano -> m:Peano -> o:Peano -> { n = m => m = o => plus n m = plus m o } @-}
thmPlusId' :: Peano -> Peano -> Peano -> Proof
thmPlusId' n m o = trivial

{-@ thmMultOPlus :: n: Peano -> m: Peano -> { mult (plus O n) m = mult n m } @-}
thmMultOPlus :: Peano -> Peano -> Proof
thmMultOPlus n m = trivial

{-@ thmMultS1 :: m:Peano -> n:Peano -> { S n = m => mult m (S n) = mult m m } @-}
thmMultS1 :: Peano -> Peano -> Proof
thmMultS1 m n = trivial

-- | Proof by Case Analysis ----------------------------------------------------

{-@ thmPlus1Neq0 :: n:Peano -> { beq (plus n (S O)) O = False } @-}
thmPlus1Neq0 :: Peano -> Proof
thmPlus1Neq0 O     = trivial
thmPlus1Neq0 (S n) = trivial

{-@ thmNegbInvolutive :: b:Bool -> { negb (negb b) == b} @-}
thmNegbInvolutive :: Bool -> Proof
thmNegbInvolutive True  = trivial
thmNegbInvolutive False = trivial

{-@ thmAndbCom :: a:Bool -> b:Bool -> {andb a b == andb b a} @-}
thmAndbCom True  True  = trivial
thmAndbCom True  False = trivial
thmAndbCom False True  = trivial
thmAndbCom False False = trivial

{-@ thmAndbExch :: a:Bool -> b:Bool -> c:Bool
                -> { andb (andb a b) c == andb (andb a c) b }
  @-}
thmAndbExch :: Bool -> Bool -> Bool -> Proof
thmAndbExch True  True  True  = trivial
thmAndbExch True  True  False = trivial
thmAndbExch True  False True  = trivial
thmAndbExch True  False False = trivial
thmAndbExch False True  True  = trivial
thmAndbExch False True  False = trivial
thmAndbExch False False True  = trivial
thmAndbExch False False False = trivial

{-@ thmAndbTrueElim2 :: b:Bool -> c:Bool -> { andb b c = True => c = True } @-} -- TODO:trivial
thmAndbTrueElim2 :: Bool -> Bool -> Proof
thmAndbTrueElim2 False False = andb False False *** QED
thmAndbTrueElim2 False True  = andb False True  *** QED
thmAndbTrueElim2 True  False = andb True  False *** QED
thmAndbTrueElim2 True  True  = andb True  True  *** QED

{-@ thm0NeqPlus1 :: n:Peano -> { beq O (plus n (S O)) = False } @-}
thm0NeqPlus1 :: Peano -> Proof
thm0NeqPlus1 O     = trivial
thm0NeqPlus1 (S n) = trivial


{-@ thmIdTwice :: f:(x:Bool -> {v:Bool | v = x}) -> b:Bool -> { f (f b) = b } @-}
thmIdTwice :: (Bool -> Bool) -> Bool -> Proof
thmIdTwice f b
  =   f (f b)
  ==. b
  *** QED

{-@ thmNegTwice :: f:(x:Bool -> {v:Bool | v = negb x}) -> b:Bool -> { f (f b) = b } @-}
thmNegTwice :: (Bool -> Bool) -> Bool -> Proof
thmNegTwice f b
  =   f (f b)
  ==. b ? thmNegbInvolutive b
  *** QED

-- RJ: You can rewrite
--   (m : Peano) -> (n : Peano) -> (eqProof : m = n) -> (beq m n = True)

{-@ thmEqBeq :: m:Peano -> n:Peano -> { v : Proof |  m = n } -> { beq m n = True } @-}
thmEqBeq :: Peano -> Peano -> Proof -> Proof
thmEqBeq O O _         = trivial
thmEqBeq (S m) (S n) _ = thmEqBeq m n trivial