I'm working on a Haskell version of the assignments in Modern Compiler implementation in ML. I currently have a working front end and IR translation module, but they are using some very bad hacks which I want to avoid.
The hacks are mainly global IORefs created through unsafePerformIO. Those global IORefs are used to implement the symbol module described in the book.
symbol is a light-weight representation for a String. They way the module works is is basically by keeping track of a Map and an Int. For each string that I have not yet seen before assign it the next integer, and modify the stored map and counter in the IORef.
symbol module is used by the parser and the IR translation module. The parser uses it to translate String into symbols, while IR uses another module that's based upon the symbol module to create unique function labels (the language I'm implementing supports nested function declarations).
Now, I would really like to get rid of the IORefs and unsafePerformIOs. So I was thinking I can use StateT (Map, Int) ParsecT [Token] () m instead so that the map and counter is kept inside a state monad. While the computation for IR translation will be kept inside the inner monad m.
But this doesn't really work, because I'd like to be able to still use combinators like try, optionMaybe from the Parsec library.
In short, the imperative analogy is that I have a module A, whose functionality is accessed by two other modules B and C (could be more). A itself needs to keep track of some states, and B, C might or might not perform stateful computations. How would one translate such a relationship into Haskell?
I would love to hear some advice on how to structure code and how to design a stack of monads for this kind of problem.
Aucun commentaire:
Enregistrer un commentaire