{-# LANGUAGE GADTs #-}

import Control.Monad
import Data.Either

data Expr a where
  I :: Int -> Expr Int
  B :: Bool -> Expr Bool
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq :: Eq a => Expr a -> Expr a -> Expr Bool

eval :: Expr a -> a
eval (I n) = n
eval (B b) = b
eval (Add e1 e2) = eval e1 + eval e2
eval (Mul e1 e2) = eval e1 * eval e2
eval (Eq e1 e2) = eval e1 == eval e2
{--

getInts :: Expr -> Expr -> Maybe (Int, Int)
getInts e1 e2 = do
  r1 <- eval e1
  r2 <- eval e2
  guard (isLeft r1 && isLeft r2)
  let (Left i1) = r1
      (Left i2) = r2
   in return (i1, i2)

eval :: Expr -> Maybe (Either Int Bool)
eval (I i) = Just (Left i)
eval (B b) = Just (Right b)
eval (Add e1 e2) = do
  (i1, i2) <- getInts e1 e2
  return $ Left (i1 + i2)
eval (Mul e1 e2) = do
  (i1, i2) <- getInts e1 e2
  return $ Left (i1 * i2)
eval (Eq e1 e2) = do
  r1 <- eval e1
  r2 <- eval e2
  guard (isLeft r1 == isLeft r2)
  case r1 of
    Left i1 ->
      let (Left i2) = r2
       in return $ Right (i1 == i2)
    Right b1 ->
      let (Right b2) = r2
       in return $ Right (b1 == b2) --}
