The Typeclassopedia — request for feedback

I have just submitted a draft article for inclusion in the Monad.Reader entitled “The Typeclassopedia”. I will let the abstract speak for itself:

The standard Haskell libraries feature a number of type classes with algebraic or categorical underpinnings. Becoming a fluent Haskell hacker requires intimate familiarity with them all, yet acquiring this familiarity often involves combing through a mountain of tutorials, blog posts, mailing list archives, and IRC logs.

The goal of this article is to serve as a starting point for the student of Haskell wishing to gain a firm grasp of its standard type classes. The essentials of each type class are introduced, with examples, commentary, and extensive references for further reading.

I would love feedback from anyone, from the newest newb to the expertest expert, who would be kind enough to take a look. Particular types of feedback I would appreciate include:

  • Are there parts that are confusing or could be worded more clearly?
  • Are there parts that are stated incorrectly?
  • Do you know of any additional references that could be included?

I am looking for more references for Foldable, Traversable, and Comonad in particular, so if you know of any good resources/examples/papers related to any of those, please let me know.

At 48 pages and 110 citations, the article is rather hefty, so I certainly don’t expect most people to read through all of it anytime soon—but even if you only take a look at a section or two about which you are particularly interested and/or knowledgeable, your feedback would be greatly appreciated! I hope that this can become a valuable reference for the Haskell community.

Edit, 16 March 2009: a revised and updated version of the Typeclassopedia has now been published in the Monad.Reader.

About Brent

Associate Professor of Computer Science at Hendrix College. Functional programmer, mathematician, teacher, pianist, follower of Jesus.
This entry was posted in haskell, teaching, writing and tagged , , , . Bookmark the permalink.

54 Responses to The Typeclassopedia — request for feedback

  1. Colin Ross says:

    I have started reading through it, and my first impressions are that this is exactly the sort of thing that I need!

    In particular, the quote “Hmm, it doesn’t compile.
    . .maybe I’ll stick in an fmap here…nope, let’s see…maybe I need another (.) somewhere? …umm…” rings all too true. Although, it is usually liftM rather than fmap, although having just looked them up on Hoogle, they are actually very similar.

    Anyway, just giving you some positive feedback to reassure you that this (mammoth!) undertaking is definitely appreciated.

    As you say, there is no substitute for experience, and I do find that as I write more and larger Haskell programs, the intuition does slowly come. And it’s all good fun too.

  2. Good stuff!

    The last sentence on (>>) ends abruptly (p. 13).

  3. Rob MacAulay says:

    I have been a haskell lurker for many a year, but have not yet actually _done_ anything. As you say, there are reflexes that must be acquired. Your article does seem to fill a gap; I particularly like the references to other papers – they look both comprehensive and interesting.

    I’m still getting lost in various parts, but thats just down to low-wattage in the brain department, I think.

  4. Rob says:

    Great work! I hope my criticism below doesn’t come across too negatively.

    Personally, I find the wealth of footnotes slightly hampers the article’s readability, and I’d prefer the short listings to be inlined where they occur. This is particularly noticable at the bottom of page 3, where the functor listing is not in view. Hard problem, I know.

    I haven’t gotten too far yet. The identity functor as “tainted” values was new to me (very nice!), and I’m wondering whether the concept doesn’t fit Applicative even better than Monad? At least, the example computations all fit into applicative, and it’s not clear to me why you should be able to fold doubly tainted values to just tainted values (join).

    Cheers
    Rob

  5. Felipe says:

    Hi!

    On page 13, the note about “_ >> m” is incomplete.

    Thanks for the text!

  6. Felipe says:

    Also on page 18 (>>=) is written as (>>=.

  7. Pingback: Haskell resource: Typeclassopedia | Colin Ross

  8. Yitz Gale says:

    Great article! A few issues (so far):

    is used way before it is defined – first used in Listing 8 (ZipList), not defined until two pages later, just after Listing 10 (Applicative law).

    Pointed should indeed have a law in my opinion. You need some kind of separability – like injectivity. Otherwise, const Nothing qualifies as a valid pure for Maybe, for example. I’m not sure what the correct law is though – ask the CT people.

    -Yitz

  9. Yitz Gale says:

    s/Data.Applicative/Control.Applicative/

  10. C. Smith says:

    RE: footnote #2
    Typeclass can be one word, as evidenced by your title, with the ‘t’ capitalized and the -opedia suffix appended. ;)
    Great paper. A Haskell neophyte thanks you. More later.

  11. Yitz Gale says:

    Some text is missing at the end of the second paragraph
    after Listing 11 (Monad type class).

  12. Steve Hicks says:

    Very nice! Several comments:
    (1) the arrowhead in Fig 1 from Monoid to Foldable crosses in a confusing way the arrow from Applicative to Monad (not to be confused with an Arrow from an Applicative to a Monad…)
    (2) You’re missing parens around <$ on page 11.
    (3) Page 15: there is no puts (at least, not in the mtl I have)
    (4) Page 19: y is bound to the result of c.
    (5) On page 21 when you say that StateT s Maybe a loses its state upon failure, it might be helpful to give the types of runStateT and runMaybeT, since (at least in my mind) the statements seem backwards at first glance.

    You lost me at ArrowLoop – I called up GHCi and tried to figure out what it means to have a variable on both sides of the = in a let (eg. let x=x*x in x) but was never able to get anything other than an error… But the first 37 pages are certainly very thorough!

  13. Eric Kow says:

    This might not be worth the effort, but I wonder if it would be helpful for each section (say, Monad) to start with a mini version of Figure 1 showing just the local neighbourhood for the particular typeclass? (so we would just have Applicative pointing to Monad, pointing to MonadFix, etc).

  14. Simon Meier says:

    Great work! I already had the chance to acquire some intuition for many of the type classes you describe. However, seeing them nicely assembled helped me reorder this intuition…freeing room for more cool Haskell stuff :P

    Furthermore, I’d like to reference your typeclassopedia from the Haskell links for the University Course (http://www.infsec.ethz.ch/education/ss09/fmfp/haskell_links) I’m doing the exercise classes for. Thus I’m looking forward to the announcement of the final version or at least a stable link.

  15. Reid Barton says:

    On page 26, “discussion monoids” (across two lines) should be “discussion of monoids”.

    There’s a missing ) on page 29 after Traversable.

  16. Louis Wasserman says:

    The reason I’m okay with the fail method is for one and only one reason: the Maybe monad, where fail _ = Nothing. This has the effect that any failed pattern match in the Maybe monad simply returns Nothing, which is a seriously useful side effect, especially when combined with MaybeT…

  17. Louis Wasserman says:

    One additional thing: a lot of my intuition on Arrows comes from the idea that an arrow that isn’t a monad is precisely an arrow that cannot implement ArrowApply, meaning that you cannot, in general, “get the output” of an arrow within another arrow save by composing it with other arrows. This makes it much clearer to me why such seemingly useless methods such as first are required: every piece of data in use by an arrow must be passed through the arrow to the other end, because there’s no other way to bring it through to future computation, because we can’t apply arrows to little bits of our data and get their output. Does this make sense?

  18. Reid Barton says:

    Also, Uustalu’s name is misspelled on page 40.

  19. Porges says:

    Louis: We have the MonadPlus class for this :)

    > mzero :: m a

  20. Great stuff, great read!

    Small comment: “But fmap doesn’t give us the tools to do anything with a function which is itself in a context.” doesn’t seem to be fully correct:
    > fmap ($ True) :: Functor F => F (Bool -> a) -> F a
    does something with a function with context. Maybe you need to say “But fmap doesn’t give us the tools to do work with a function in a context and a value in another context.”?

  21. David Christiansen says:

    Great article and idea! I think this really fills a gap.

    But it would be really fantastic if it were in the form of HTML with images rather than a PDF, maybe even as a part of the wiki on Haskell.org. That would make it much easier to find for beginning-to-intermediate Haskell coders.

    Fantastic work!

  22. Kai says:

    This should be required reading for any haskell beginner.

    Thanks for the effort, I wanted something like this for sooooo long.

  23. newsham says:

    Wow. Very excellent prose, and the bibliography is amazing. I learned a bit, and it brought together a lot of ideas I knew a little bit about but hadn’t thought of how they were interconnected. I really liked the simpler presentation of the monad laws in terms of fish. I also like the introduction to new classes not yet in the base libs I have. I really wish this document was around when I was learning these ideas.
    “a value of type Arrow a => a b c can be thought of as a computation which takes values of type a as input and produces values of type c as output.” Should read “takes values of type b as input”.
    I kind of expected to see the fish operator in the discussion of the Kleisli arrow.
    I thought you should have mentioned liftM when discussing the monad law relating monads to functors. (The last law says that fmap = liftM, no? This seems like a much simpler way to state it than xs >>= return . f).
    I’m yearning for more on comonads. I guess I’ll have to chase the biblio.
    Thanks for the coverage of foldable and traverse. These are subjects I havent studied enough of yet and hopefully your paper will motivate me to start using them.

  24. newsham says:

    Oh, I forgot to mention, I really like your explanation of join in terms of trying to implement bind using just Applicative primitives. This is the first description of “join” that really gelled for me.

  25. Ashley Yakeley says:

    Instances of each class that are not instances of more specific classes would be useful. Such as: something that’s a Functor but not Pointed, something that’s a Pointed but not Applicative, etc.

    “Pointed has no associated laws to worry about.”

    Actually I think Pointed instances must satisfy

    fmap ab (pure a) = pure (ab a)

  26. Ashley Yakeley says:

    Hmm. ((,) a) is a Functor that probably shouldn’t be made a Pointed.

  27. Joe Thornber says:

    Page 33:

    “Arrow a => a b c can
    be thought of as a computation which takes values of type a as input, and produces
    values of type c as output”

    Should be takes values of type _b_ ?

  28. Andrew Cave says:

    I agree with David, I would much rather see this in a wiki.

  29. Wow! Looks terrific so far. Until when will suggestions be helpful?

    One request so far: use “(~>)” instead of “a” for the type constructor parameter to Category and Arrow. For instance:

    class Category (~>) => Arrow (~>) where
    arr :: (a -> b) -> (a ~> b)
    first :: (a ~> b) -> (a,c) ~> (b,c)
    second :: (a ~> b) -> (c,a) ~> (c,b)
    (***) :: (a ~> b) -> (a’ ~> b’) -> ((a,a’) ~> (b,b’)
    (&&&) :: (a ~> b) -> (a ~> b’) -> (a ~> (b,b’)

  30. > Hmm. ((,) a) is a Functor that probably shouldn’t be made a Pointed.

    I’d hope ((,) a) would be made a Pointed, consistently with its Applicative. Ashley — please say more about your preference not to have a pair Pointed.

  31. Oops — lost code formatting in my (~>) example. Is there to enter code and keep the formatting?

  32. Pingback: Typeclassopedia — a generic response « blog :: Brent -> [String]

  33. mightybyte says:

    Outstanding work. This is high quality material that fills an important gap. It was as if you were writing straight to me. I think the bibliography alone would have been a valuable reference for me. IMO this is a valuable companion to Real World Haskell. I do have one suggestion. In several places you mention things that are left as an exercise for the reader. It would be nice for me if you had answers to all of these exercises. I’m sure they’re out there already, but having them all in one place would be convenient.

  34. BMeph says:

    Joachim’s comment (https://byorgey.wordpress.com/2009/02/16/the-typeclassopedia-request-for-feedback/#comment-1093) is especially poignant, but hopefully no new user will feel betrayed to discover the existence of the loeb function…

    loeb :: (Functor f) => f (f b) -> f b
    loeb xs = fmap ($ loeb xs ) xs

    Hmm, maybe it’s all because of that suspicious “fmap ($…)” construction.

  35. Ashley Yakeley says:

    ((,) a) is not an Applicative actually. For instance, ((,) Char) is not an Applicative. This is because there’s no good value for “pure 3 :: (Char, Int)”.

    It looks like “Monoid a => (,) a” is Applicative

  36. Ashley Yakeley says:

    BMeph, surely loeb should have a type more like “f (f b -> b) -> f b” (with some constraint on f)?

  37. BMeph says:

    @Ashley Yakeley (and newsham): Yes, my mistake, I should have written:

    loeb :: (Functor f) => f (f b -> b) -> b

    However, I still stand by my suspicion of the trouble that comes from the “fmap ($ … )” construction.

  38. Page 23 states that the [a] instance of Monoid defines mconcat = concat, and footnote 14 says this illustrates a case where mconcat is defined as something more efficient than the default.

    However, lambdabot says concat’s definition is simply foldr (++) [], which is the same thing as mconcat’s default definition. In addition, Data/Monoid.hs in the ghc 6.10.1 source doesn’t even define mconcat in the Monoid [a] instance.

  39. Simon says:

    “So it would not make sense to say instance Functor Integer, but it could make sense to say instance Functor Maybe.”

    Typo?

  40. DavidA says:

    Hi. This article certainly clarified several things for me. However, I think it still leaves the reader unclear about the motivation behind some of the abstractions, notably Applicative, Arrow and Comonad. Obviously, with so much material to cover, you’re going to have to leave a lot to the further reading. However, I think it would be nice if for each of the abstractions, you at least discussed when it would be appropriate to use it. (For example, you could explain *why* the Haskell XML toolkit uses Arrows).

  41. Steven says:

    Great stuff — I’m definitely in the target audience.
    p. 10: You use <$> in the “more idiomatically” section, but doesn’t get described until p. 11. (And on p. 11, again it is used before it is properly introduced near the bottom of the page.)

  42. Deech says:

    This is really great! Thanks for doing this. But a couple of noob questions:

    Is ‘pure’ is just another kind of ‘lift’? The article suggests that fmap lifts but ‘pure’ seems to do essentially the same thing without first applying a function. If I can why is ‘pure’ necessary since ‘fmap’ already exists?

    Thanks …
    deech

  43. Deech says:

    Pardon the grammatical errors above. It’s what happens when you cut-and-paste while rephrasing. Blogging software with some sort of grammar compiler would be nice.

  44. Jared says:

    @mightybyte. Ditto!

    Amazing piece of work, Brent. I wish I’d read this years ago. Reading this has elevated my perspective over the Haskell landscape; understanding these concepts is crucial for anyone to become a fluent Haskeller instead of just a dabbler. The order of presentation makes this happen.

    I wish this were an appendix in RWH because it also helps RWH make much more sense. Maybe I’ll print it out and paste it in there. Typeclassopedia should be mandatory reading for all Haskellers.

    The only problem is: how do we abbreviate the name with a snappy acronym like “RWH”?

    “Tcop”?

  45. tehgeekmeister says:

    on page thirteen, end of the fourth paragraph from the bottom, there is a sentence i’m dying to read the end of but can’t. because it’s not there. =P

  46. b_jonas says:

    In the section about monoids, you mention that monads can actually be viewed as a monoid: there it would be nice to mention that this is not the monoid instance typically defined for library monads (like Maybe). Also, I think you should at least mention Writer or WriterT somewhere in that section.

    (Also, I find it ironic how the section about Monad talks about intuition, after your previous blog post on monad tutorials. I didn’t even dare to read that section in case it would clash with my intuition about monads.)

  47. IO monad is described incorrectly. See http://www.haskell.org/haskellwiki/IO_inside and http://mailman.science.ru.nl/pipermail/clean-list/1999/001036.html

    The latter is from Clean mail list, but it helps to understand what exactly the RealWorld from the first article means.

    The IO Monad is not magical. There’s nothing which makes it unique. Implementation of any function can be different in different compilers, this is true even for basic functions such as Prelude.foldr.

    All monads are pure, and none of them require special compiler support. There are no functions with side effects in Haskell — everything, including IO, is pure.

  48. Wei says:

    I also spotted the issue found by Kevin Ballard, regarding the mappend’s definition for lists.

  49. Wei says:

    Sorry, I meant mconcat.

  50. Pingback: Monad.Reader #13 is out! « blog :: Brent -> [String]

  51. Jonas says:

    Hi,

    is there a standalone version of the article in the Monad.Reader, maybe as HTML? I keep looking at the typeclassopedia a lot and it’s annoying having to scroll to it in the Monad.Reader PDF all the time. :)

Leave a reply to b_jonas Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.