96

Hackage has several packages for monad transformers:

  • mtl: Monad transformer library
  • transformers: Concrete functor and monad transformers
  • monads-fd: Monad classes, using functional dependencies
  • monads-tf: Monad classes, using type families
  • monadLib: A collection of monad transformers.
  • mtl-tf: Monad transformer library using type families.
  • mmtl: Modular Monad transformer library
  • mtlx: Monad transformer library with type indexes, providing 'free' copies.
  • compose-trans: Composable monad transformers

(and maybe I missed some)

Which one shall we use?

mtl is the one in the Haskell Platform, but I keep hearing on reddit that it's uncool.

But what's bad about choice anyway, isn't it just a good thing?

Well, I saw how for example the authors of data-accessor had to make all these to cater to just the popular choices:

  • data-accessor-monadLib library: Accessor functions for monadLib's monads
  • data-accessor-monads-fd library: Use Accessor to access state in monads-fd State monad class
  • data-accessor-monads-tf library: Use Accessor to access state in monads-tf State monad type family
  • data-accessor-mtl library: Use Accessor to access state in mtl State monad class
  • data-accessor-transformers library: Use Accessor to access state in transformers State monad

I imagine that if this goes on and for example several competing Arrow packages evolve, we might see something like: spoonklink-arrows-transformers, spoonklink-arrows-monadLib, spoonklink-tfArrows-transformers, spoonklink-tfArrows-monadLib, ...

And then I worry that if spoonklink gets forked, Hackage will run out of disk space. :)

Questions:

  • Why are there so many monad transformer packages?
  • Why is mtl [considered] uncool?
  • What are the key differences?
  • Most of these seemingly competing packages were written by Andy Gill and are maintained by Ross Paterson. Does this mean that these packages are not competing but rather work together in some way? And do Andy and Ross consider any of their own packages as obsolete?
  • Which one should you and I use?
jeremy
  • 9,965
  • 4
  • 39
  • 59
yairchu
  • 23,680
  • 7
  • 69
  • 109
  • 2
    This link helped me understand mtl vs transformers http://www.haskell.org/haskellwiki/Monad_Transformer_Library – Brandon Cook Jul 13 '14 at 22:39
  • 2
    Scroll down for [@jberryman comment](http://stackoverflow.com/questions/2769487/mtl-transformers-monads-fd-monadlib-and-the-paradox-of-choice#comment8791863_2769664)! Use mtl or transfomers, they became compatible! – Sophie Mar 27 '17 at 14:46

3 Answers3

74

A bunch of them are almost completely equivalent:

  • mtl uses GHC extensions, but transformers is Haskell 98.
  • monads-fd and monads-tf are add-ons to transformers, using functional dependencies and type families respectively, both providing the functionality in mtl that's missing from transformers.
  • mtl-tf is mtl reimplemented using type families.

So essentially, mtl == transformers ++ monads-fd, mtl-tf == transformers ++ monads-tf. The improved portability and modularity of transformers and its associated packages is why mtl is uncool these days, I think.

mmtl and mtlx both seem to be similar to and/or based on mtl, with API differences and extra features.

MonadLib seems to have a rather different take on matters, but I'm not familiar with it directly. Also seems to use a lot of GHC extensions, more than the others.

At a glance compose-trans seems to be more like metaprogramming stuff for creating monad transformers. It claims to be compatible with Control.Monad.Trans which... I guess means mtl?

At any rate, I'd suggest the following decision algorithm:

  • Do you need standard monads for a new project? Use transformers & co., help us lay mtl to rest.
  • Are you already using mtl in a large project? transformers isn't completely compatible, but no one will kill you for not switching.
  • Does one of the other packages provide unusual functionality that you need? Might as well use it rather than rolling your own.
  • Still unsatisfied? Throw them all out, download category-extras, and solve all the world's problems with a page and a half of incomprehensible abstract nonsense breathtakingly generic code.
imz -- Ivan Zakharyaschev
  • 4,921
  • 6
  • 53
  • 104
C. A. McCann
  • 76,893
  • 19
  • 209
  • 302
  • 2
    if mtl == transformers ++ monads-fd, couldn't it just be implemented in this way? (as a phase towards replacing it) that would rid of the need to have stuff like data-accessor-mtl – yairchu May 05 '10 at 13:09
  • 1
    @yairchu: They're not 100% compatible, though--if nothing else, I think there are minor differences in the API. Switching over wouldn't be difficult for most packages using `mtl`, but it probably isn't something that can safely be done automatically or behind the scenes. – C. A. McCann May 05 '10 at 14:07
  • 1
    @camccann: I see. But there's still some unification that could be done in a backwards-compatible way by extracting some common stuff out. The MonadTrans class, which is exactly the same, can be put in its own package. Then there won't be a need for splits like MaybeT/MaybeT-transformers. Another is the Identify monad, which even gets recreated in TypeCompose because Conal doesn't want to depend on mtl. – yairchu May 05 '10 at 20:54
  • 2
    @yairchu: Well yes, but what do you expect me to do about it? :) Maintaining backwards compatibility is never as easy as it seems, and changing key libraries takes time, effort, and some degree of community support. The monad transformer situation is a known problem but I don't think it's anyone's top priority by a long shot. – C. A. McCann May 06 '10 at 02:12
  • 6
    @yairchu: thats basically what is being done. the next major version of mtl should be be a stub that imports transformers + monads-fd, and compatibility with that version will be the deciding factor. Libraries will then be able to be individually updated so that they are compatible with both mtl 1.1 and 1.2, and then apps get pigeonholed into whichever version is installed or is required by their most restrictive library dependency. – Edward Kmett May 06 '10 at 03:47
  • @camccann: Just trying to discuss what would be a good direction for the library to take, I'm not expecting you to implement it. Although, I never saw you and superman at the place... :) – yairchu May 06 '10 at 08:55
  • @camccann: Re "Maintaining backwards compatibility is never as easy as it seems". Making mtl take the exact same MonadTrans class it has from a different package (which has no module clashes with it) is backward compatible. You're suggesting that it's not that easy, i.e that it doesn't work. How so? – yairchu May 06 '10 at 09:04
  • 2
    The libraries mailing list is currently discussing moving MonadIO (and possibly MonadTrans out of mtl and into base. Although, it has been hung up on whether to extract MonadIO or a more general MonadBase despite the fact that "MonadBase" needs MPTCs, fundeps, etc. – Edward Kmett May 06 '10 at 11:37
  • 1
    @yairchu: Nothing specific, just bitter experience of major changes that "shouldn't" impact functionality generally resulting in at least a couple severe headaches anyway. Edward Kmett seems to have covered the actual current situation in much better detail than I could. – C. A. McCann May 06 '10 at 13:01
  • 31
    Since I found this post extremely informative. I thought I would update other googlers: mtl now depends on transformers, monads-fd is now a stub around mtl. So use mtl if you need the extra goodies it has, or just import transformers if it has everything you need. – jberryman Sep 04 '11 at 04:53
  • I take issue with the brief characterization of monadLib as using significant extensions vs the others (as it stands today). MonadLib uses only simple and safe extensions where as MTL uses more dangerous tools such as UndecidableInstances and CPP. – Thomas M. DuBuisson Aug 02 '16 at 05:03
20

For the moment? You should probably use mtl. What is happening is that the transformers library is being factored out of the MTL in a fashion that monads-fd and monads-tf can co-exist peacefully, but at last check that was not yet the case.

When that happens you'll be able to import monads-fd and transformers and get (almost) the same interface, with the exception that State, etc. will be an alias for StateT.

So I'd write to mtl, but not rely on the fact that State, Reader, etc. are currently data as they will be replaced with types.

MonadLib is another alternative that Iavor has been working on, which can be safely used because it doesn't share any module names with the others, but which has a fairly different usage pattern.

Edward Kmett
  • 29,632
  • 7
  • 85
  • 107
  • 4
    Co-exist in what sense? Used by the same package? Imported into the same module? Combined into the same transformer stack? Mixing fundeps and TFs strikes me as a bad idea, in general. Anyway, I haven't made extensive use of `transformers` & co. yet but didn't notice any problems other than some minor API differences vs. `mtl` when switching some (fairly simple) code. – C. A. McCann May 05 '10 at 00:47
  • 4
    The problem comes down to the fact that you can only load one package that provides a given module. So if you use a library that uses mtl, even internally, you can't import an alternative. Currently a healthy percentage of hackage uses the mtl internally in some way. A number of folks prefer to use type families, and monads-tf gives them that, but keep in mind that at the moment, until the transformers + monads-fd refactoring is completed this locks that code out from using any libraries that transitively require MTL. That includes some pretty big ticket items. – Edward Kmett May 06 '10 at 03:37
  • 1
    Using transformers+monads-(tf|fd) will in the long term avoid that pickle, but we aren't there yet. In the meantime the preponderance of usage is in favor of mtl. The upgrade path looks to be that the next major version of the mtl will be redefined as a stub that imports monads-fd and transformers. The major version break provides a good way to state in your cabal file that you don't care which version you get (i.e. you don't care about State being a type alias or a data type) and once that major version bump happens then you need not care if every library you use all share the same biases. – Edward Kmett May 06 '10 at 03:41
  • 1
    So, ultimately your experience so far is exactly what transformers/monads-(tf|fd) are designed to support. But, what was realized after they were written was that the community is pretty abymsally bad at switching libraries, when there isn't a compelling reason to jump and a ton of legacy reasons to stay. Hence the need to redefine mtl and make the upgrade path clear. – Edward Kmett May 06 '10 at 03:44
  • Awesome, thanks for the detailed clarification! Obviously, the code I switched had few external dependencies--mostly FFI bindings, I think. I also didn't realize that module name conflicts were that... invasive, I guess? That does make things awkward indeed. :( – C. A. McCann May 06 '10 at 03:59
  • This was written in 2010. Is it still correct to use mtl in 2016? – Vlad the Impala Dec 12 '16 at 18:41
  • Yep. Even, now, in 2017 that I got around to answering. =) – Edward Kmett Jan 08 '17 at 00:56
18

The factoring out Edward Kmett mentions in his answer was completed in late 2010. Its end result was monads-fd, built upon transformers, becoming version 2 of mtl. As a consequence of the ubiquitousness of mtl, monads-tf never really caught on. As of early 2017, mtl and transformers are the only monad transformer libraries that see widespread usage.

Community
  • 1
  • 1
duplode
  • 33,731
  • 7
  • 79
  • 150