This should be ground reading for anyone who wishes to engage in conversation about the names of Haskell abstractions or the decision to write a “monad tutorial”.
I agree that Monoid should be Monoid rather than “Appendable” and same with Functor vs. “Mappable” (or Monad vs. “Flatmappable”, which would just be ridiculous).
Monad tutorials, on the other hand, while stereotypically useless to the point of being a cliché, aren’t necessarily doomed except for the problem of “learning Monad” requiring that one learn a bunch of other concepts: type classes, type-level operators (since Functor and Monad are type classes on type constructors rather than concrete types) and so on. The laws are the easy part, especially if introduced in tandem with Kleisli arrows, and essentially a victory lap after the ground work is done. So one could write a “good monad tutorial”, if it were possible to teach all of that material quickly. That said, I haven’t found a way, unless we expand the definition of tutorial to include “this will take multiple sittings, for most people”. At which point, it’s more of a course than a tutorial.
In other words (and this may be what you’re getting at) the problem with Monad tutorials isn’t necessarily that monads are too hard, but that it’s hard to come up with a good monad tutorial that doesn’t teach a significant amount of Haskell, at which point you’re beyond what can be taught in one sitting.
I wonder if it’s worth teaching IO first, and then bindIO, and then pointing out that what we’d call foo -> bar -> baz in ML would be Foo -> Bar -> IO Baz unless the compiler could detect an absence of side effects. I think that before people get IO (and see how much less principled most languages are in their type systems!) it’s hard to get them motivated enough to do the work necessary to learn Monad unless they already have that motivation in another way (i.e. an interest in Haskell and a willingness to become a beginner again).
foo -> bar -> baz
Foo -> Bar -> IO Baz
I suppose I argue against the monad tutorial in the same way that I’d argue against a Group tutorial. Usually “tutorial” aims at a concrete thing not a class of abstract objects. It just doesn’t work well. This post suggests cleanly how “monad” is meaningful and yet different from “maybe” and introducing “typeclasses” as the difficulty is confusing a what with a how, I think.
one possibility is to explain monads with code in some more familiar language (i’ve seen several blogposts doing that for ruby, scheme, python, etc.). the primary “aha!” moment has nothing to do with haskell, type classes, functors, or anything esoteric; it’s just taking the idea of passing a function to an opaque container and letting the container apply the function to the data within, and understanding why you might want to use this particular abstraction.
All of those languages lack the abstraction capabilities to cleanly talk about monads or functors. The best you can do while remaining familiar is an approximation and I’ve found this often confuses ideas more than it clarifies.
Perfect explanation of what I’ve been trying to get at in my discussions with people about monads and other functional concepts: understanding via metaphor only takes you so far when you’re dealing with mathematical laws. A monad is anything that fits the monad laws. That’s all. (I’ve even written about it here.) Thanks for the link!
Yeah, this is a really important mindset issue that I’ve had to reverse-engineer by noticing that apparently anyone with a formal math education has it, and nobody else does. :) The definition is the thing.
It still gives me a lot of trouble because I feel as though I have nothing to pin the concept to to help me remember it… but at least now I know that what I should be doing is comparing it to related concepts in terms of how it differs from those definitions, not trying to compare it to my practical experience. I’m not honestly sure how math enthusiasts do this; I guess I’d need to understand a critical mass of basic formalisms.
[Comment removed by author]
Well, thank you. :) That sounds actionable.
Modular arithmetic is not a “metaphor” for groups, it is an example, a special case that explains some, but not all, of what groups are for.
To explain groups, you keep piling on examples. Real-life things like mirror symmetries, shuffles of card decks, and rubix cubes. Then move on to math topics that usually come before groups: number systems, matrices, permutations, plane geometry translations, rotations, reflections.
When you see that all of these things can be studied in the same way using the group axioms, you have an answer to “what’s a group?”
I enjoyed this. I work in the education industry and it continuously astounds me how high the barrier of vocabulary can be to newcomers. It’s easily half of the pain.
The GoF metaphors aren’t “cryptic”.
A group isn’t a clock, but for many people abstractions need to be built up inductively. A group is the thing that’s the same about a clock, the symmetries of an object, and the various other examples. Teaching the definitions top-down is often unhelpful - if you were teaching someone how to do clock arithmetic you wouldn’t start with the group laws. It’s only when someone wants to work with a general group (and already has several examples) that the abstract concept becomes valuable.
I think the question of is-ness comes down to the fundamental difference between OO and functional style. In OO an object exists, first and foremost, and what it is is a very useful question. In functional style things are largely characterized by what they do. Honestly I think this ends up being a weak point for functional - I’m playing with an idea for a strongly typed language/style that eschews anonymous functions, or at least makes a fundamental distinction between values that have identity and values that don’t.
Appealing to intuition in mathematics is hazardous.
We all perceive analogies differently. As Dijkstra is quoted in the article, formal abstractions let us evade the pervasive imprecision of the human mind. A clock is a good example for explaining groups, but imperfect. Parts of the world use a 24-hour clock, other parts use a 12-hour clock. Even modular arithmetic won’t work reliably here.
If you want to introduce groups using vague analogies, you should be sufficiently vague, and even this will bite you in rear.
Formalisms may be inaccessible at first but what I remember from math studies in university is that things became a lot easier when I stopped trying to grok concepts using plain intuition.
It’s not vague or imprecise. Integers under modular arithmetic literally do form a group. (Likewise the definition of a Functor literally is the single method map, so there would be nothing imprecise about calling it Mappable).
I’m not arguing for intuition. I’m arguing for induction. Build up from examples to abstractions. There is no value in introducing the concept of a monad until you’ve introduced at least two specific things that form monads. Then you can show very concretely how there’s a commonality between those two things and this abstract concept lets you express that commonality.
I agree with you here. What I meant was that using clocks as a particular example for groups (via modular arithmetic) can be dangerous when you take time systems into consideration. Therefore, there are caveats to using real-world analogies.
I don’t think clocks or any of the GoF lingo are particularly suitable for being used inductively. But as you showed, Mappable is.