module Main where import Data.Map as Map data Runnable = Name String | Add Runnable Runnable | Block (Map String Runnable) Runnable | I Integer deriving (Eq, Ord, Show) run :: Runnable -> Map String Runnable -> Either [String] Integer -- Instances -- Integers resolve to Right Integer run (I v) _ = Right v -- For Names -- look up their expression in the scope, then evaluate -- if name is out of scope, raise an error run (Name n) s = which (Map.lookup n s) where which Nothing = Left ["Variable not in scope: " ++ n] which (Just v) = run v s -- For Addition -- Run a, Run b, Add their results -- Raise appropriate errors where necessary run (Add a b) s = geta (run a s) where geta (Left es) = Left (es ++ ["In lhs of expression: " ++ show (Add a b)]) geta (Right a') = getb a' (run b s) getb _ (Left es) = Left (es ++ ["In rhs of expression: " ++ show (Add a b)]) getb a' (Right b') = Right (a' + b') -- For Blocks -- Run the block's expression under a new scope -- (merging the current with the block's scope definition) run (Block s' e) s = result $ run e (Map.union s' s) where result (Left es) = Left (es ++ ["In block: " ++ show (Block s' e)]) result (Right v) = Right v instance Num Runnable where (+) = undefined (-) = undefined (*) = undefined negate = undefined signum = undefined fromInteger = I main = mapM_ print [ run 5 Map.empty , run (Name "a") Map.empty , run (Name "a") (fromList [("a", 6)]) , run (Add 6 3) Map.empty , run (Add (Name "a") 7) (fromList [("a", 10)]) , run (Block (fromList [("a", 10)]) (Name "a")) Map.empty ]