Is Haskell's `Const` Functor analogous to the constant functor from category theory?
I understand that many of the names in Haskell are inspired by category theory terminology, and I'm trying to understand exactly where the analogy begins and ends.
The Category Hask
I already know that Hask is not (necessarily) a category due to some technical details about strictness/laziness and seq, but let's put that aside for now. For clarity,
- The objects of
Haskare concrete types, that is, types of kind*. This includes function types likeInt -> [Char], but not anything that requires a type parameter likeMaybe :: * -> *. However, the concrete typeMaybe Int :: *belongs toHask. Type constructors / polymorphic functions are more like natural transformations (or other more general maps fromHaskto itself), rather than morphisms. - The morphisms of
Haskare Haskell functions. For two concrete typesAandB, the hom-setHom(A,B)is the set of functions with signatureA -> B. - Function composition is given by
f . g. If we are worried about strictness, we might redefine composition to be strict or be careful about defining equivalence classes of functions.
Functors are Endofunctors in Hask
I don't think the technicalities above have anything to do with my confusion below. I think I understand it means to say that every instance of Functor is an endofunctor in the category Hask. Namely, if we have
class Functor (F :: * -> *) where
fmap :: (a -> b) -> F a -> F b
-- Maybe sends type T to (Maybe T)
data Maybe a = Nothing | Just a
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
the Functor instance Maybe corresponds to a functor from Hask to Hask in the following way:
To each concrete type
ainHask, we assign the concrete typeMaybe aTo each morphism
f :: A -> BinHask, we assign the morphismMaybe A -> Maybe Bwhich sendsNothing ↦ NothingandJust x ↦ Just (f x).
The Constant (endo)Functor
The constant (endo)functor on a category C is a functor Δc : C → C mapping each object of the category C to a fixed object c∈C and each morphism of C to the identity morphism id_c : c → c for the fixed object.
The Const Functor
Consider Data.Functor.Const. For clarity, I will redefine it here, distinguishing between the type constructor Konst :: * -> * -> * and the data constructor Const :: forall a,b. a -> Konst a b.
newtype Konst a b = Const { getConst :: a }
instance Functor (Konst m) where
fmap :: (a -> b) -> Konst m a -> Konst m b
fmap _ (Const v) = Const v
This type checks because the data constructor Const is polymorphic:
v :: a
(Const v) :: forall b. Konst a b
I can buy that Konst m is an endofunctor in the category Hask, since in the implmenetation of fmap,
- on the left-hand side,
Const vmanifests itself as aKonst m a, which is ok due to polymorphism - on the right-hand side,
Const vmanifests itself as aKonst m b, which is ok due to polymorphism
But my understanding breaks down if we try to think of Konst m :: * -> * as a constant functor in the category-theoretic sense.
What is the fixed object? The type constructor
Konst mtakes some concrete typeaand gives us aKonst m a, which, at least superficially, is a different concrete type for everya. We really want to map each typeato the fixed typem.According to the type signature,
fmaptakes anf :: a -> band gives us aKonst m a -> Konst m b. IfKonst mwere analogous to the constant functor,fmapwould need to send every morphism to the identity morphismid :: m -> mon the fixed typem.
Questions
So, here are my questions:
In what way is Haskell's
Constfunctor analogous to the constant functor from category theory, if at all?If the two notions are not equivalent, is it even possible to express the category-theoretic constant functor (call it
SimpleConst, say) in Haskell code? I gave it a quick try and ran into the same problem with polymorphism wrt phantom types as above:
data SimpleKonst a = SimpleConst Int
instance Functor SimpleConst where
fmap :: (a -> b) -> SimpleConst a -> SimpleConst b
fmap _ (SimpleConst x) = (SimpleConst x)
If the answer to #2 is yes, If so, in what way are the two Haskell functions related in the category-theoretic sense? That is,
SimpleConstis toConstin Haskell as the constant functor is to__?__in category theory?Do phantom types pose a problem for thinking of
Hasklike a category? Do we need to modify the definition ofHaskso that objects are really equivalence classes of types that would otherwise be identical if not for the presence of a phantom type parameter?
Edit: A Natural Isomorphism?
It looks like the polymorphic function getConst :: forall a,b. Konst a b -> a is a candidate for a natural isomorphism η : (Konst m) ⇒ Δm from the functor Konst m to the constant functor Δm : Hask → Hask, even though I haven't been able to establish yet whether the latter is expressible in Haskell code.
The natural transformation law would be η_x = (Konst m f) . η_y. I'm having trouble proving it, since I'm not sure how to formally reason about the conversion of a (Const v) from type Konst m a to Konst m b, other than handwaving that "a bijection exists!".
Related References
Here is a list of possibly related questions / references not already linked above:
- StackOverflow, "Do all Type Classes in Haskell have a Category-Theoretic Analogue?"
- StackOverflow, "How are functors in Haskell related to functors in category theory?"
- WikiBooks, Haskell/Category Theory
Id aandaare isomorphic, with an obvious bijection. Now can you find one betweenKonst a xanda? – n. 'pronouns' m. Apr 21 at 6:34