[Haskell-beginners] How to remove some duplication from this code?

Peter Hall peter.hall at memorphic.com
Tue Dec 13 22:40:13 CET 2011


I'm following this article about GADTs
[http://en.wikibooks.org/wiki/Haskell/GADT] and it suggests, as an
exercise, to handle invalid trees at runtime, without GADTs, when
evaluating a simple arithmetic syntax tree. My attempt is below.

It seems to work, but I could do with some feedback, as it isn't quite
satisfactory. It feels like I should be able to remove some of the
duplicated code in the eval function, and also in evalIntExpr and
evalBoolExpr, which are identical except for having Left and Right
reversed.

Thanks,

Peter


-------- Arithmetic.hs

module Arithmetic where
import Data.Maybe

data Expr = I Int
    | B Bool
    | Add Expr Expr
    | Mult Expr Expr
    | Eq Expr Expr

eval :: Expr -> Maybe (Either Bool Int)
eval (B b) = return $ Left b
eval (I i) = return $ Right i
eval (Mult e1 e2) = do
    a1 <- evalIntExpr e1
    a2 <- evalIntExpr e2
    return $ Right $ a1 * a2
eval (Add e1 e2) = do
    a1 <- evalIntExpr e1
    a2 <- evalIntExpr e2
    return $ Right $ a1 + a2
eval (Eq e1 e2) = do
    a1 <- evalIntExpr e1
    a2 <- evalIntExpr e2
    return $ Left $ a1 == a2


evalIntExpr :: Expr -> Maybe Int
evalIntExpr e = eval e >>= unwrap
        where
            unwrap (Right x) = Just x
            unwrap (Left x) = Nothing


evalBoolExpr :: Expr -> Maybe Bool
evalBoolExpr e = eval e >>= unwrap
        where
            unwrap (Left x) = Just x
            unwrap (Right x) = Nothing



------- Main.hs

module Main (
    main
) where

import Arithmetic
import Data.Maybe
import Data.Either

test :: Expr
test = Eq
        (Mult
            (Add
                (I 1)
                (I 2)
            )
            (I 5)
        )
        (I 15)

main :: IO ()
main = do
    putStrLn $ case eval test of
        Nothing -> "Invalid expression"
        Just (Left x) -> show x
        Just (Right x) -> show x



More information about the Beginners mailing list