-- | Arithmetic Quiz
-- An exercise with recursive data types
-- Functional Programming course 2016.
-- Thomas Hallgren

import Control.Monad(forever)
import Test.QuickCheck

main = do putStrLn "Welcome to the Arithmetic Quiz!"
          forever quiz

quiz =
    do e <- generate rExpr'
       putStr ("\n"++showExpr e++" = ")
       answer <- getLine
       let correct = show (eval e)
       putStrLn (if answer == correct
                 then "Correct!"
                 else "Wrong! The correct answer is: "++correct)


-- | A representation of simple arithmetic expressions
data Expr = Num Integer
          | Add Expr Expr
          | Mul Expr Expr
            deriving (Eq{-,Show-})

ex1 = Num 2
ex2 = Add (Num 1) (Num 2)
ex3 = Mul (Add (Num 1) (Num 2)) (Num 3)
ex4 = Add (Num 1) (Mul (Num 2) (Num 3))


-- | Computing the value of an expression
eval :: Expr -> Integer
eval (Num n)   = n
eval (Add a b) = eval a + eval b
eval (Mul a b) = eval a * eval b


-- | Showing expressions
showExpr :: Expr -> String
showExpr (Num n)   = show n
showExpr (Add a b) = showExpr a ++ "+" ++ showExpr b
showExpr (Mul a b) = showFactor a ++ "*" ++ showFactor b


showFactor :: Expr -> String
showFactor (Add a b) = "("++showExpr (Add a b)++")"
showFactor e         = showExpr e


instance Show Expr where show = showExpr

-- * Generating arbitrary expressions

rExpr :: Int -> Gen Expr
rExpr size = frequency [(1,rNum),(size,rBin)]
  where
    rNum = elements [Num n | n<-[0..10]]
    rBin = do op <- elements [Add,Mul]
              let size' = size `div` 2
              a <- rExpr size'
              b <- rExpr size'
              return (op a b)

rExpr' = rExpr 3 `suchThat` notNum

notNum (Num _) = False
notNum _       = True

instance Arbitrary Expr where
  arbitrary = sized rExpr