Search code examples
haskellfunctorcategory-theorylifting

Does a functor always return a lifted type in haskell when the fmap transformation is applied?


Let's say I have an Int and I apply fmap transformation using the Maybe as a functor, I get a wrapped type, i.e., Maybe Int. So can I consider this as lifting? If so does a functor always return a lifted type?


Solution

  • fmap always takes a function of type a -> b, and gives you a function of type f a -> f b, for some type constructor f. So if you call the application of the type constructor f to the type a "lifting", then yes, fmap always gives you a function that works on "lifted types".1

    The builtin Haskell type class Functor has as members type constructors of kind * -> *: things that can be applied to any type you like, to produce a new type (like Maybe in your example). In category theory terms, the type constructor itself (e.g. Maybe) represents the mapping from objects of the source category to the target category, and fmap provides the mapping of morphisms (remembering that the Hask catogory has Haskell types as objects and Haskell functions as morphisms).

    So Haskell Functor can only represent endofunctors on the category Hask, since maps Haskell types & functions to Haskell types & functions. But it can't even represent any possible endofunctor, since we can't use it to map objects (types) arbitrarily. My Haskell functor can't map Int to Maybe String and Char to Bool, it must map each type to "the same type" under a type constructor (as Maybe maps Int to Maybe Int, Char to Maybe Char, Maybe (Maybe (Maybe Bool)) to Maybe (Maybe (Maybe (Maybe Bool))), etc). Each Haskell Functor's destination category is an entire mirror image of Hask nested under the functor's type constructor.

    So Haskell's Functor class is quite a restricted version of the general notion of a category theory functor, and even quite restricted compared to the notion of "an endofunctor on Hask". But if we are talking specifically about Haskell Functors, then yes, a function that is the result of fmap will always return (and take) values in a "lifted" type.


    1 Be aware that "lifting" and "lifted" as applied to things in Haskell have a number of established meanings in different contexts, so don't automatically assume anything else you see talking about "lifted types" means the same thing as in this discussion.