Use of Haskell state monad a code smell?

前端 未结 8 2081
悲哀的现实
悲哀的现实 2020-12-22 19:56

God I hate the term \"code smell\", but I can\'t think of anything more accurate.

I\'m designing a high-level language & compiler to Whitespace in my spare time

相关标签:
8条回答
  • 2020-12-22 20:42

    I've written multiple compilers in Haskell, and a state monad is a reasonable solution to many compiler problems. But you want to keep it abstract---don't make it obvious you're using a monad.

    Here's an example from the Glasgow Haskell Compiler (which I did not write; I just work around a few edges), where we build control-flow graphs. Here are the basic ways to make graphs:

    empyGraph    :: Graph
    mkLabel      :: Label -> Graph
    mkAssignment :: Assignment -> Graph  -- modify a register or memory
    mkTransfer   :: ControlTransfer -> Graph   -- any control transfer
    (<*>)        :: Graph -> Graph -> Graph
    

    But as you've discovered, maintaining a supply of unique labels is tedious at best, so we provide these functions as well:

    withFreshLabel :: (Label -> Graph) -> Graph
    mkIfThenElse :: (Label -> Label -> Graph) -- branch condition
                 -> Graph   -- code in the 'then' branch
                 -> Graph   -- code in the 'else' branch 
                 -> Graph   -- resulting if-then-else construct
    

    The whole Graph thing is an abstract type, and the translator just merrily constructs graphs in purely functional fashion, without being aware that anything monadic is going on. Then, when the graph is finally constructed, in order to turn it into an algebraic datatype we can generate code from, we give it a supply of unique labels, run the state monad, and pull out the data structure.

    The state monad is hidden underneath; although it's not exposed to the client, the definition of Graph is something like this:

    type Graph = RealGraph -> [Label] -> (RealGraph, [Label])
    

    or a bit more accurately

    type Graph = RealGraph -> State [Label] RealGraph
      -- a Graph is a monadic function from a successor RealGraph to a new RealGraph
    

    With the state monad hidden behind a layer of abstraction, it's not smelly at all!

    0 讨论(0)
  • 2020-12-22 20:42

    Well, don't use monads. The power of functional programming is function purity and their reuse. There's this paper a professor of mine once wrote and he's one of the guys who helped build Haskell.

    The paper is called "Why functional programming matters", I suggest you read through it. It's a good read.

    0 讨论(0)
提交回复
热议问题