Lecture 3 — 2020-01-30
Our first interpreter
This lecture is written in literate Haskell; you can download the raw source.
We wrote our first interpreter. We defined a grammar like so:
p, q in Prop ::= ⊤ | ⊥ | p ∧ q | p ∨ q | ¬ p | p ⇒ q
p1 = ⊤ ∧ ⊥
p2 = ⊥ ∨ ⊥
We talked about what the propositions p1 and p2 might mean… nothing, yet! We had to define an interpretation function, where we interpret elements of Prop as booleans:
2 = { true, false} with standard operations &&, ||, and !
interp : Prop -> 2
interp(⊤) = true
interp(⊥) = false
interp(p ∧ q) = interp(p) && interp(q)
interp(p ∨ q) = interp(p) || interp(q)
interp(¬ p) = !interp(p)
interp(p ⇒ q) = !interp(p) || interp(q)
Then we did the same in Haskell:
data Prop =
T
| F
| And Prop Prop
| Or Prop Prop
| Not Prop
| Implies Prop Prop
p1 :: Prop
p1 = T `And` F
interp :: Prop -> Bool
interp T = True
interp F = False
interp (And p q) = interp p && interp q
interp (Or p q) = interp p || interp q
interp (Not p) = not $ interp p
interp (Implies p q) = not (interp p) || interp q
We didn’t write a “pretty printer” for Prop
, but we could have using the Show
type class. This one prints out appropriately parenthesized concrete syntax. It was a little aggressive, though, printing way too many parentheses:
instance Show Prop where
show T = "T"
show F = "F"
show (And a b) =
"And (" ++ show a ++ ") (" ++ show b ++ ")"
show (Or a b) =
"Or (" ++ show a ++ ") (" ++ show b ++ ")"
show (Implies a b) =
"Implies (" ++ show a ++ ") (" ++ show b ++ ")"
show (Not a) = "Not (" ++ show a ++ ")"
We didn’t have time, but I alluded to the possibility of manipulating the abstract syntax of Prop
in its own right; for example, we can translate away any use of Implies
.
-- | Compile away implication in propositions.
--
-- Examples:
--
-- >>> interp (compile (Implies (Or T F) F))
-- False
--
-- >>> compile (Or T F)
-- Or T F
--
-- >>> compile (Or (Implies F T) F)
-- (Or (Or (Not F) T) F)
compile :: Prop -> Prop
compile (Implies p q) = Not (compile p) `Or` compile q
compile (And p q) = And (compile p) (compile q)
compile (Or p q) = Or (compile p) (compile q)
compile (Not p) = Not $ compile p
compile T = T
compile F = F
The sample code above are doctests, a nice way of writing your tests inline.