Heh, yeah, I guess so!
I agree with nearly everything everyone said, but: The Pure type class should be in parallel with the Apply type class, Apply should not be a superclass of Pure. One reason is, again, van-Laarhoven encoding of optics:
- Functor gives you lenses (exactly one focus)
- Applicative gives you traversals (any number of foci)
- Pure gives you affine traversals (0 or 1 focus)
- Apply gives you traversals with 1 or more foci
Each is useful on their own, and different. They form a true diamond.
Ed’s reflections on class Pointed
also probably apply here.
Adding pure
into Functor
would restrict the functionality of the typeclass for types that have a “conditional” Applicative instance, such as:
instance Monoid a => Applicative (Const a) where ...
instance Monoid a => Applicative ((,) a) where ...
Both of these need mempty
to create pure
values, but this is not required by their Functor
instances for fmap
.
Expanding on the semigroupoids
comment by @Ambrose: For intuition on why pure
should not be in a superclass of the class that provides <*>
, you might want to consider a rather similar situation with Semigroups (which provide the squashing operation <>
, similar to <*>
) and Monoids (which add the unit-creating mempty
, similar to pure
). The actual connection is exemplified by Ap.