{-# LANGUAGE GADTs, ExistentialQuantification #-}
module Typed where
import qualified Expr as E
import Maybe (fromJust)
data Expr t where
Lit :: (Eq t, Show t) => t -> Expr t
(:+) :: Expr Int -> Expr Int -> Expr Int
(:==) :: (Eq t, Show t) => Expr t -> Expr t -> Expr Bool
If :: Expr Bool -> Expr t -> Expr t -> Expr t -- ADDED a)
eval :: Expr t -> t
eval (Lit x) = x
eval (e1 :+ e2) = eval e1 + eval e2
eval (e1 :== e2) = eval e1 == eval e2
eval (If e1 e2 e3) = if eval e1 then eval e2 else eval e3 -- ADDED b)
eOK :: Expr Int
eOK = If (Lit False) (Lit 1) (Lit 2 :+ Lit 1736)
data Type t where
TInt :: Type Int
TBool :: Type Bool
data TypedExpr = forall t. (Eq t, Show t) => Expr t ::: Type t
data Equal a b where
Refl :: Equal a a
-- | The type comparison function returns a proof that the types we
-- compare are equal in the cases that they are.
(=?=) :: Type s -> Type t -> Maybe (Equal s t)
TInt =?= TInt = Just Refl
TBool =?= TBool = Just Refl
_ =?= _ = Nothing
infer :: E.Expr -> Maybe TypedExpr
infer e = case e of
E.LitN n -> return (Lit n ::: TInt)
E.LitB b -> return (Lit b ::: TBool)
r1 E.:+ r2 -> do
e1 ::: TInt <- infer r1
e2 ::: TInt <- infer r2
return (e1 :+ e2 ::: TInt)
r1 E.:== r2 -> do
e1 ::: t1 <- infer r1
e2 ::: t2 <- infer r2
Refl <- t1 =?= t2
return (e1 :== e2 ::: TBool)
E.If r1 r2 r3 -> do -- ADDED c)
e1 ::: TBool <- infer r1
e2 ::: t2 <- infer r2
e3 ::: t3 <- infer r3
Refl <- t2 =?= t3
return (If e1 e2 e3 ::: t2)
check :: E.Expr -> Type t -> Maybe (Expr t)
check r t = do
e ::: t' <- infer r
Refl <- t' =?= t
return e
test1R = read "1+2 == 3"
test1 = Maybe.fromJust (infer test1R)
infixl 6 :+
infix 4 :==
infix 0 :::
instance Show (Type t) where
show TInt = "Int"
show TBool = "Bool"
instance Show TypedExpr where
show (e ::: t) = show e ++ " :: " ++ show t
instance Show t => Show (Expr t) where
showsPrec = showsPrecExpr
showsPrecExpr :: Show t => Int -> Expr t -> ShowS -- ADDED d)
showsPrecExpr p e = case e of
Lit n -> shows n
e1 :+ e2 -> showParen (p > 2) $
showsPrec 2 e1 . showString " + " . showsPrec 3 e2
e1 :== e2 -> showParen (p > 1) $
showsPrec 2 e1 . showString " == " . showsPrec 2 e2
If e1 e2 e3 -> showParen (p > 0) $ -- ADDED d)
showString "if " . shows e1 .
showString " then " . shows e2 .
showString " else " . shows e3