
Hugh Perkins wrote:
That works just fine as long as the only thing eval has to cope with is print statements (so eval has type IO ()), but I'm guessing the clean solution is to thread a Map.Map through that somehow?
You could do that but your code starts to become messy and you'll hit other limitations. The standard approach to this problem is to use a State monad. Since you are already using one monad, IO, you can can stack the monads using Monad transformers which makes them both available (although you will need to use liftIO, see below) import Control.Monad import Control.Monad.State import Data.Map type Env = Map String String type InterpM = StateT Env IO eval :: a -> InterpM t instance Eval Print where eval (Print value) = liftIO $ putStrLn value You access and store the state using get and put. For example: eval (Variable s) = do s <- get lookup the value and return it. There is a paper on using Monads with interpreters (http://web.cecs.pdx.edu/~mpj/pubs/modinterp.html) and an example described at http://www.haskell.org/haskellwiki/Libraries_and_tools/HJS. Mark