8

I'm looking at the documentation for Data.Traversable and came across fmapDefault - https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base/Data-Traversable.html#g:3

fmapDefault :: Traversable t => (a -> b) -> t a -> t b

The documentation states that -

This function may be used as a value for fmap in a Functor instance, provided that traverse is defined.

So presumably it can be used to derive an fmap for a Traversable instance. However, Traversable has Functor as a superclass.

class (Functor t, Foldable t) => Traversable t where
    ...

So you cannot define a Traversable instance without defining the Functor instance first! And wherever you have a Traversable, you have access to an fmap, which is equivalent to (and perhaps more efficient than) fmapDefault.

So where would one use fmapDefault, instead of the much more familiar fmap?

Anupam Jain
  • 7,851
  • 2
  • 39
  • 74
  • 2
    "You cannot define a `Traversable` instance without defining the `Functor` instance first!" Well, "first" is such a squirrely term... – Daniel Wagner Jul 05 '15 at 20:06
  • Yeah, that was a bit of a brain fart. Like assuming 1 comes before 2, due to years of counting procedurally from 0-10. And then you consider the question - what comes first, '-1' or '-2', and are enlightened. – Anupam Jain Jul 06 '15 at 11:41

1 Answers1

11

It allows you to write

data Foo a = ...

instance Functor Foo where -- we do define the functor instance, but we “cheat”
  fmap = fmapDefault       -- by using `Traversable` in its implementation!

instance Traversable Foo where
  traverse = ...           -- only do this manually.

That said, I don't think this is really sensible. Functor instances are usually trivial to do by hand, and the obvious implementation will indeed likely be more efficient than a Traversable derived one. Usually, the instance can in fact be created automatically:

{-# LANGUAGE DeriveFunctor #-}

data Foo a = ...
       deriving (Functor)
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • *Usually, the instance can in fact be created automatically [...]* Isn't that always the case? – jub0bs Jul 05 '15 at 11:17
  • 4
    @Jubobs: not quite, for some GADTs I have gotten errors about well-kindedness with `DeriveFunctor`. But possibly this was just a bug in GHC-7.8. – leftaroundabout Jul 05 '15 at 11:19
  • 2
    Damn, I had subconciously assumed that 'subclass' definitions cannot refer to 'superclass' definitions. Obviously that is a somewhat of an arbitrary requirement in hindsight. That's what you get when you have to use half of the time. – Anupam Jain Jul 05 '15 at 11:24
  • @leftaroundabout Good to know. Thanks. – jub0bs Jul 05 '15 at 12:58
  • 3
    @Jubobs `DeriveFunctor` also bails out if it sees a type family used in certain ways, even in cases where you can prove it's still a valid functor. – Carl Jul 05 '15 at 15:00