I've been reading up on Applicative Functors and I am having difficulty reconciling a mismatch in the respective terminologies of category theory and functional programming.
Although I have looked over various blogs, the most complete resources that I have been using for this research are:
In category theory, a functor is a morphism from a source category to a target category (in a category of categories). The "category of categories" has a collection of objects that contains both the source and target categories and a collection of functors that contains: the source category's identity functor; the target category's identity functor; and, the functor connecting the source to the target (If the source category is the same as the target category and the functor in question is the identity, then there need only be that one functor).
In functional programming, applicative functors are described as a pair of operations:
pure : a -> f a
<*> : f ( a -> b) -> f a -> f b
. What interpretation makes clear the correspondence between the the functional programming definition of an applicative functor and the category theoretical definition of a functor?
More specifically, what parts of the tuple (pure,<*>)
correspond to:
Notes: I recognize that this may be an incomplete metaphor, and there may not be a one-to-one correspondence for each of the concepts that I mentioned. I have purposely refrained from sharing my speculation about the apparent correspondences here in order to keep my question simple and to avoid confounding the issues further.
Functors are the structure-preserving maps of categories; they can be composed, so there is a (large) category Cat consisting of small categories and functors. Informally, there is also a (huge) category CAT consisting of all categories and functors.
Functor in Haskell is a kind of functional representation of different Types which can be mapped over. It is a high level concept of implementing polymorphism. According to Haskell developers, all the Types such as List, Map, Tree, etc. are the instance of the Haskell Functor.
In functional programming, a functor is a design pattern inspired by the definition from category theory, that allows for a generic type to apply a function inside without changing the structure of the generic type. This idea is encoded in Haskell using type class.
A Functor is kind of mapping of objects and morphisms that preserves composition and identity. We have two Categories: A and B . In Category A we have two objects a and b with morphism f . Our Functor is a mapping of objects a and b to Fa and Fb and mapping of morphisms, in this case single morphism: f to Ff .
Paraphrasing this answer: Applicative functors are functors for which there is also a natural transformation that preserve monoidal structure of their source/target categories. In the case of Haskell's Applicative
endofunctors (because their source and target categories is Hask), the monoidal structure is the Cartesian product. So for an Applicative
functor there are natural transformations φ: (f a, f b) -> f (a, b)
and ι: () -> f ()
. So we could define Applicative
as
class Functor f => Applicative' f where φ :: (f a, f b) -> f (a, b) ι :: f () -- it could be \() -> f (), -- but \() -> ... is redundant
This definition is equivalent to the standard one. We can express
φ = uncurry (liftA2 (,)) = \(x, y) -> (,) <$> x <*> y ι = pure ()
and conversely
pure x = fmap (\() -> x) ι f <*> x = fmap (uncurry ($)) (φ (f, x))
So pure
and <*>
is an alternative way how to define this natural transformation.
It's probably simpler to look at the class Functor
first (which is a superclass of Applicative
). Applicative
corresponds to a "lax monoidal functor", as the first paper you linked to points out. The definition of Functor
is:
class Functor f where fmap :: (a -> b) -> f a -> f b
An instance of Functor
is a type constructor (of kind * -> *
). An example is Maybe
.
The category we're talking about is the category "Hask" that has Haskell types as objects and (monomorphic) Haskell functions as morphisms. Every instance of Functor
(and Applicative
, Monad
, etc.) is an endofunctor in this category, i.e. a functor from the category to itself.
The two maps of the functor -- Haskell-types-to-Haskell-types and Haskell-functions-Haskell-functions -- are the type constructor f
and the function fmap
.
For example, Int
and Maybe Int
are both objects in Hask; Maybe
maps from the former to the latter. If chr :: Int -> Char
, then fmap
maps it to fmap chr :: Maybe Int -> Maybe Char
. The Functor
laws correspond to the categorical functor laws.
In the case of Applicative
, Functor
is a superclass, so everything I just said applies. In this particular case you can implement fmap
using pure
and <*>
-- liftA f x = pure f <*> x
-- so the two parts of the functor that you were looking for are f
and liftA
. (But note that other formulations of Applicative
don't let you do that -- in general you would rely on the Functor
superclass.)
I'm not quite sure what you mean here by "the category where the functor lives".
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