packages feed

lambda-calculator-1.1.0: test/Language/Lambda/Examples/BoolSpec.hs

module Language.Lambda.Examples.BoolSpec where

import Test.Hspec

import Language.Lambda.HspecUtils

spec :: Spec
spec = describe "Bool" $ do
  -- Bool is the definition of Booleans. We represent bools
  -- using Church Encodings:
  --
  -- true:  \t f. t
  -- false: \t f. f
  describe "and" $ do
    -- The function and takes two Bools and returns true
    -- iff both arguments are true
    -- 
    -- and(true,  true)  = true
    -- and(false, true)  = false
    -- and(true,  false) = false
    -- and(false, false) = false
    --
    -- and is defined by
    -- and = \x y. x y x
    it "true and true = true" $
      "(\\x y. x y x) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"

    it "true and false = false" $
      "(\\x y. x y x) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. f"
      
    it "false and true = false" $
      "(\\x y. x y x) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. f"

    it "false and false = false" $
      "(\\x y. x y x) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"

    it "false and p = false" $
      "(\\x y. x y x) (\\t f. f) p" `shouldEvalTo` "\\t f. f"

    it "true and p = false" $
      "(\\x y. x y x) (\\t f. t) p" `shouldEvalTo` "p"

  describe "or" $ do
    -- or takes two Bools and returns true iff either argument is true
    -- 
    -- or(true,  true)  = true
    -- or(true,  false) = true
    -- or(false, true)  = true
    -- or(false, false) = false
    --
    -- or is defined by
    -- or = \x y. x x y
    it "true or true = true" $
      "(\\x y. x x y) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"
    
    it "true or false = true" $
      "(\\x y. x x y) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. t"
      
    it "false or true = true" $
      "(\\x y. x x y) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. t"

    it "false or false = false" $
      "(\\x y. x x y) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"

    it "true or p = true" $
      "(\\x y. x x y) (\\t f. t) p" `shouldEvalTo` "\\t f. t"

    it "false or p = p" $
      "(\\x y. x x y) (\\t f. f) p" `shouldEvalTo` "p"
      

  describe "not" $ do
    -- not takes a Bool and returns its opposite value
    --
    -- not(true)  = false
    -- not(false) = true
    --
    -- not is defined by
    -- not = \x. x (\t f. f) (\t f. t)
    it "not true = false" $
      "(\\x. x (\\t f. f) (\\t f. t)) \\t f. t" `shouldEvalTo` "\\t f. f"

    it "not false = true" $
      "(\\x. x (\\t f. f) (\\t f. t)) \\t f. f" `shouldEvalTo` "\\t f. t"
      
  describe "if" $ do
    -- if takes a Bool and two values. If returns the first value
    -- if the Bool is true, and the second otherwise. In other words,
    -- if p x y = if p then x else y
    --
    -- if(true,  x, y) = x
    -- if(false, x, y) = y
    -- 
    -- if is defined by
    -- if = \p x y. p x y
    it "if true 0 1 = 0" $
      "(\\p x y. p x y) (\\t f. t) (\\f x. x) (\\f x. f x)"
        `shouldEvalTo` "\\f x. x"

    it "if false 0 1 = 1" $
      "(\\p x y. p x y) (\\t f. f) (\\f x. x) (\\f x. f x)"
        `shouldEvalTo` "\\f x. f x"

    it "it true p q = p" $
      "(\\p x y. p x y) (\\t f. t) p q" `shouldEvalTo` "p"

    it "it false p q = q" $
      "(\\p x y. p x y) (\\t f. f) p q" `shouldEvalTo` "q"