MTL's Unfortunate MT Anchor
thatsthejoke.jpg
<p class="date">2016-07-26</p>
An unpacking of a cryptic tweet suggesting that Monad Transformers have limited the popularity of the design used by the Monad Transformer Library,
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Haskell programming techniques were set back by mtl being associated with monad transformers.</p>— Anthony Cowley (@acowley) <a href="https://twitter.com/a_cowley/status/753679659443838976">July 14, 2016</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
MT = Meh Types
Monad Transformers are not a universally popular construction in Haskell. Without veering into tutorial territory, they are a layering of type constructors that permit one to write functions that operate on the different layers while retaining a monadic API with which the whole may be manipulated. The downsides to monad transformers as provided by the transformers package are that they,
- Are not commutative
- Can impose some overhead due to traversing the layers
- Don't scale painlessly from an API perspective as it can be hard to distinguish two similar layers (e.g. two layers of
ReaderT Int (ReaderT Int m) a
) - Layer navigation with explicit
lift
applications is brittle
MTL's Value Proposition
The mtl
package directly addresses the last two points above, and incidentally offers an amelioration of the second. The primary benefit of the mtl
is that it hides the concrete (monad transformer) type, instead offering a type class API that frees the programmer from writing out lift
applications, thereby making code prettier and more amenable to changes in the specific type used. Sometimes, after adopting the mtl style of listing the constraints the supplied type must satisfy, one will flatten a stack of type constructors into one ApplicationState
(name to taste) record capable of serving all needs.
MTL in Pop Culture
An interesting non-code linguistic idiom has grown popular in the Haskell community: references to "mtl style" (example: the previous paragraph). This phrase can mean something as specific as precisely what the mtl
package does, but in its loosest form it refers simply to the use of a type class constraint in preference to a concrete type in order to avoid writing type signatures that are coupled too closely to a type design that one might prefer to have some freedom to change.
I'll draw another loose connection to the makeClassy
suite of functionality in the lens package. This approach is great because it lets you nest data structures and transparently make use of code written without any awareness of that nesting. For instance, you define a Person
data type, write some functions for working with values of that type, then define a Citizen
record that has a field of type Person
, and can immediately use lens-y code written against the Person
type on values of the Citizen
type..
Avoiding the Mainstream
While type classes provide a mechanism for the use of shared identifiers, willy nilly use of this approach has been socially discouraged because differences in meaning between uses of a shared name are a rich source of bugs and confusion. Haskellers love fmap~ping things because there are a couple equations they can rely on no matter what they are ~fmap~ping. Lenses bring with them the lens laws whose foundation is a promise not to immediately shoot you in the foot, and perhaps it is this bare minimum that lifts ~makeClassy
out of the semantics-free zone.
All of this is quite reminiscent of subtyping and interfaces (or protocols) in more mainstream, object-oriented languages. Programming to an interface is not something Haskell generally excels at outside of type classes, due in part to the very minimal module system it provides. By turning our backs on type classes with no claims to a mathematical foundation, we have wed ourselves too closely to concrete types. We astronauts of abstraction have forsaken an available abstraction to protect ourselves from those who would roughly poke us with it.
The mtl
package is carefully constructed, but I think informal uses of the mtl style phrase is a telling symptom that the benefits of the broad strokes of the mtl
design are under-appreciated. My conjecture is that while this is in part due to the noble pursuit of avoiding lawless type classes, it is also due to the fact that people just don't like monad transformers, and therefore don't have any great love for the mtl
. If the mtl
was a part of every Haskell program, rewriting a type signature from Foo -> Bar
to HasFoo t => t -> Bar
would be a borderline reflexive mechanical refactoring.