Has anyone ever encountered the Monad Transformer in the wild?

In my area of ​​business — the IT department for a financial institution — it is very common for a software component to carry a global configuration in order to record its progress, to have some kind of error handling / short circuit calculation. Things that can be modeled well with Reader-, Writer-, Maybe-monads, etc. In Haskell and composed with monad transformers.

But there are some drawbacks: the concept of monad transformers is quite complicated and difficult to understand, monad transformers lead to very complex type signatures, and they impose some performance limitation.

So, I wonder: is it better to use monad transformers when it comes to these common tasks mentioned above?

+50
design-patterns haskell monads monad-transformers
May 03 '10 at 17:37
source share
6 answers

The Haskell community is divided into this issue.

  • John Hughes reports that it is easier for him to teach monadic transformers than he is to teach monads, and that his students work better with the principle of "transformers."

  • GHC developers generally avoid monad transformers, preferring to fold their own monads, which combine all the functions they need. (Today I had nowhere to say that the GHC will not use the monad transformer that I identified three days ago.)

For me, monad transformers are very similar to point programming (i.e. programming without named variables), which makes sense; after all, they accurately program a point at the type level. I never liked dot-based programming because it is useful to be able to type in a random name.

What I observe in practice is

  • The number of monad transformers available in Hackage is very large, and most of them are quite simple. This is a classic example of a problem where it is more difficult to learn a large library than to roll up your own instances.

  • Monads, such as Writer, State, and Environment, are so simple that I don’t see much use for monad transformers.

  • Where fashionable transformers shine in modularity and reuse. This property is beautifully demonstrated by Liang, Hoodak and Jones in their famous paper Monad Transformers and Modular Interpreters .

Is it better to use monad transformers in solving the above common problems?

I would say no. Where is it best to use monad transformers, where you have a line of related abstract abstractions that you can create by creating and reusing monad transformers in different ways. In such a case, you probably developed a series of monad transformers that are important for your problem area (for example, one that was rejected for the GHC), and you (a) compose them in several ways; (b) achieve significant reuse for most transformers; (c) encapsulate something non-trivial in every monad transformer.

My monad transformer, which was rejected for the GHC, did not meet any of the criteria (a) / (b) / (c) above.

+42
May 03 '10 at 19:40
source share

The concept of monad transformers is quite complicated and hard to understand, monad transformers lead to very complex type signatures

I think this is a little exaggeration:

  • Using a specific Monad transformer stack is no more difficult than using a regular Monad. Just think about the layers / stacks and you will be fine. You almost always never have to raise a pure function (or specific I / O action) more than once.
  • As already mentioned, hide your Monad stack in newtype, use generic output and hide the data constructor in the module.
  • Try not to use a specific Monad stack in a function type signature, write generic code with types of Monad type such as MonadIO, MonadReader and MonadState (use the flexible context extension standardized in Haskell 2010).
  • Use libraries such as fclabels to reduce the effects of templates that access parts of a record in Monad.

Monad transformers are not your only options, you can write regular Monad, use Monad sequels. You have mutable references / arrays in IO (global), ST (local and managed, without I / O), MVar (synchronization), TVar (transactional).

I heard that potential performance issues with Monad transformers could be mitigated by simply adding INLINE pragmas to bind / return to the mtl / transformers library source.

+7
May 03 '10 at 19:21
source share

I recently fell for monad composition in the context of F #. I wrote a DSL that is heavily dependent on the state monad: all components rely on the state monad: a parser (syntax based on the state monad), variable mapping tables (more than one for internal types), identifier lookup tables. And since all of these components work together, they rely on the same state monad. Therefore, there is the concept of state composition, which brings together various local states and the concept of state accessories, which give each of them their own visibility at the state level.

Initially, the design was truly "just one big state monad." But then I began to need conditions with local life time, but still in the context of a “stable” state (and again all these states are controlled by state monads). To do this, I needed to introduce state monad transformers that complement the state and adapt monads together. I also added a transformer for free movement between the state monad and the continuation state monad, but I did not bother to use it.

Therefore, to answer the question: yes, monad transformers exist in the "wild." Nevertheless, I would strongly object to using them out of the box. Write your application with simple building blocks, using small hand bridges between your modules, if you end up using something like a monad transformer, that's great; Do not start from there.

And about the types of signatures: I thought of this type of programming as something very similar to playing blind chess (and I'm not a chess player): your skill level should be at the point where you “see” your functions and types Type signatures basically end up being a distraction unless you explicitly want to add type constraints for security reasons (or because the compiler forces you to give them, for example, with F # entries).

+3
Dec 07 '10 at
source share

So, something that tends to be more global, like a log or configuration, would you suggest putting an IO monad? From the look (admittedly a very limited set) of examples, I come to think that Haskell code tends to be either clean (i.e. not monadic at all) or in the IO monad. Or is it a delusion?

I think this is a fallacy, only the IO monad is not clean. monads, such as Write / T / Reader / T / State / T / ST monads, are purely functional. You can write a pure function that uses any of these monads inside, like this completely useless example:

foo :: Int -> Int foo seed = flip execState seed $ do modify $ (+) 3 modify $ (+) 4 modify $ (-) 2 

All this makes the flows / plumbing state implicitly, what you do manually yourself, explicitly, do-notation just gives you good syntactic sugar to make it look imperative. Here you cannot perform any input / output operations, you cannot name any external functions. ST monad allows you to have real mutable links in the local area, having a clean function interface, and you cannot perform any I / O operations where it is purely functional.

You cannot avoid some I / O operations, but you do not want to return to IO for everything, because everything can go there, you can launch rockets, you have no control. Haskell has abstractions for managing efficient computing with varying degrees of security / purity, the IO monad should be the last resort (but you cannot completely avoid it).

In your example, I think you should stick to using custom-made monad or monad transformers, which does the same thing as composing them with transformers. I never wrote a custom monad (but so far), but I used monad transformers quite a bit (my own code, not at work), don’t worry about them so much, use them, and it’s not as bad as you think.

Have you seen a chapter from Real World Haskell that uses monad transformers ?

+2
May 03 '10 at 10:36
source share

I think this is a fallacy, only the IO monad is not clean. monads like Write Mono / T / Reader / T / State / T / ST are purely functional.

It seems to me that more than one concept of the terms pure / unclean seems to me. Your definition of "IO = fuzzy, everything else = clean" sounds like what Peyton Jones talks about in Taming Effects ( http://ulf.wiger.net/weblog/2008/02/29/peyton-jones- taming-effects-the-next-big-challenge / ). On the other hand, Real World Haskell (on the final pages of the Monad Transformer chapter) contrasts pure functions with the monadic function as a whole - claiming you need different libraries for both worlds. By the way, it can be argued that IO is also clean, and side effects are encapsulated in a state function of type RealWorld → (a, RealWorld). In the end, Haskell calls itself a purely functional language (including IO, I suppose :-).)

My question is not so much what can be done theoretically, but what has been proven from the point of view of Software Engineering. Monad transformers allow modularity of effects (and abstractions in general), but is that direction programming supposed to go in?

+2
May 04 '10 at 8:05 a.m.
source share

When I studied monads, I created an application using the StateT ContT IO stack to create a discrete event modeling library; extensions were used to store monodal threads, with StateT holding the runnable thread queue and other queues used for suspended threads waiting for various events. It worked well enough. I could not figure out how to write a Monad instance for the newtype shell, so I just made it a type synonym and worked very well.

These days, I probably would have lowered my own monad from scratch. However, whenever I do this, I find that I look at "All About Monads" and the MTL source to remind me what the binding operations look like, so in a way I still think about the MTL stack, although the result is just a monad .

+2
May 04 '10 at 20:35
source share



All Articles