In this exercise you will write a tautology checker in Haskell for the datatype Prop found in the library file Prop.hs.
A tautology is a propositional statement that is true for every possible assignment of all its propositional variables (e.g. LetterP n) to true or false.
The strategy for defining your tautology checker is:
As you work through this exercise we expect you to learn the following:
To get started on this problem set you will need the files: (1) Prop.hs, (2) Blocks.hs, and (3) ForwardProver.hs. These are the same files you used in Exercise 1 so you probably already have them. You might want to right click and download fresh copies into your Haskell code directory just in case they have changed.
You will also need the Problem 1 solution stub. Right click on this link and download a coipy of the stub in your Haskell code directory. Name the file <yourname>P1.hs. The stub looks like this.
module Assignment1 where
import Prop
alphaRename :: Eq a => Prop a -> (Prop Int,[(a,Int)])
alphaRename term = (sub pairs term,pairs)
  where vs = letters term
        pairs = zip vs [0..]
sub :: (Eq t) => [(t, b)] -> Prop t -> Prop b
sub pairs (AndP x y)     = AndP     (sub pairs x) (sub pairs y)
sub pairs (OrP x y)      = OrP      (sub pairs x) (sub pairs y)
sub pairs (ImpliesP x y) = ImpliesP (sub pairs x) (sub pairs y)
sub pairs (NotP x)       = NotP     (sub pairs x)
sub pairs TruthP         = TruthP
sub pairs AbsurdP        = AbsurdP
sub pairs (LetterP x) =
  case lookup x pairs of
    Nothing -> error "Unknown LetterP"
    Just n -> LetterP n
assignments :: Int -> [[Bool]]
assignments 0 = []
assignments 1 = [[True],[False]]
assignments n = undefined
eval :: Prop Int -> [Bool] -> Bool
eval (LetterP x) assign    =  assign !! x
eval (AndP x y) assign     = undefined
eval (OrP x y) assign      = undefined
eval (ImpliesP x y) assign = undefined
eval (NotP x) assign       = undefined
eval TruthP assign         = undefined
eval AbsurdP assign        = undefined
tautology :: (Eq a) => Prop a -> Tautology Int
tautology term = undefined
	 | 
|---|
To get you started I have defined a number of functions (alphaRename and sub) and partially defined several others (assignments, eval, and tautology). It's your job to complete the partially defined functions.
A function is partially defined if it has the token undefined in its body. The token undefined is a perfectly fine Haskell expression and the stub file will compile just as you download it. It won't, of course, compute any answers until you replace every undefined with working code.
Let's study the fully defined functions, this study should help you complete the partially defined ones. The first fully defined function is alphaRename.
alphaRename :: Eq a => Prop a -> (Prop Int,[(a,Int)])
alphaRename term = (sub pairs term,pairs)
  where vs = letters term
        pairs = zip vs [0..]
		
sub :: (Eq t) => [(t, b)] -> Prop t -> Prop b
sub pairs (AndP x y)     = AndP     (sub pairs x) (sub pairs y)
sub pairs (OrP x y)      = OrP      (sub pairs x) (sub pairs y)
sub pairs (ImpliesP x y) = ImpliesP (sub pairs x) (sub pairs y)
sub pairs (NotP x)       = NotP     (sub pairs x)
sub pairs TruthP         = TruthP
sub pairs AbsurdP        = AbsurdP
sub pairs (LetterP x) =
  case lookup x pairs of
    Nothing -> error "Unknown LetterP"
    Just n -> LetterP n