I think I found a flaw in the hackage article for Control.Applicative
.
As a description of the applicative functor laws, it says:
class Functor f => Applicative f where
A functor with application, providing operations to embed pure expressions (
pure
), and sequence computations and combine their results (<*>
).A minimal complete definition must include implementations of these functions satisfying the following laws:
identity
pure id <*> v = v
composition
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
homomorphism
pure f <*> pure x = pure (f x)
interchange
u <*> pure y = pure ($ y) <*> u
(note that this does not say anything about fmap) and it states that these laws determine the Functor
instance:
As a consequence of these laws, the
Functor
instance for f will satisfyfmap f x = pure f <*> x
I thought at first this was obviously wrong. That is, I guessed there must exist a type constructor t
satisfying the following two conditions:
t
is an instance of Applicative
fulfilling the rules above, andinstance (Functor t)
(i.e. there are two distinct functions fmap1, fmap2 :: (a->b) -> (t a->t b)
,
satisfying the functor laws).If (and only if) the above is correct, the above statement must be rewritten to
The Functor instance for f must satisfy
fmap f x = pure f <*> x
As a consequence of these laws, this satisfies the
Functor
laws.
which is clearly correct, no matter whether my guess is right or not.
My question is: is my guess correct? Is there a t
with the desired conditions?
What follows is the explanation of what I thought during trying to answer this question by myself.
If we were mere mathematicians uninterested in actual Haskell programming, we could easily answer this question affirmatively. In fact,
t = Identity
newtype Identity a = Identity {runIdentity :: a}
meets the requirements 1 and 2 above (in fact, almost anything will do). Indeed, Identity
is trivially an instance of Functor
and Applicative
, as defined in Data.Functor.Identity
. (This satisfies fmap f = (pure f <*>)
.)
To define another "implementation" of instance (Functor f)
, Take, for each type a
, two functions
transf_a, tinv_a :: a -> a
such that
tinv_a . transf_a = id
(This is, set-theoretically, easy). Now define
instance (Functor Identity) where
fmap (f :: a->b) = Identity . transf_b . f . tinv_a . runIdentity
This satisfies the Functor
laws and is a different implementation from the trivial one if there are
x :: a
f :: a -> b
such that
f x /= transf_b $ f $ tinv_a x
But it is not at all obvious whether we can do it in Haskell. Is something like:
class (Isom a) where
transf, tinv :: a -> a
instance (Isom a) where
transf = id
tinv = id
specialized instance (Isom Bool) where
transf = not
tinv = not
possible in Haskell?
I forgot to write something very important. I recognize Control.Applicative
as part of GHC base package, so I am also interested in whether the answer to my question changes with any GHC language extensions, such as FlexibleInstances
or OverlappingInstances
, which I don't understand yet.
Any type in Haskell can have at most one instance of Functor
, so your guess is not correct: For no type t
(whether or not it's an instance of Applicative
) can there exist two different implementations of instance (Functor t)
. See: http://article.gmane.org/gmane.comp.lang.haskell.libraries/15384
It is a property of the type a -> a
that there are only two inhabitants of it, namely id :: a -> a
(defined as id x = x
) and bottom :: a -> a
defined as bottom = error "Infinite loop."
.
If we restrict ourselves to only the first case as "reasonable", we come to an important mathematical theorem, which is that there is at most one function fmap
of type forall a. forall b. (a -> b) -> f a -> f b
satisfying fmap id = id
and fmap f . fmap g = fmap (f . g)
.
If we do not, then you are correct, we have one case where fmap = undefined
and the other where fmap = (<*>) . pure
. But that's a little cheesy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With