# Profunctor
Profunctor
is a typeclass provided by the profunctors
package in Data.Profunctor
(opens new window).
See the "Remarks" section for a full explanation.
# (->) Profunctor
(->) is a simple example of a profunctor: the left argument is the input to a function, and the right argument is the same as the reader functor instance.
instance Profunctor (->) where
lmap f g = g . f
rmap f g = g . g
# Syntax
- dimap :: Profunctor p => (a -> b) -> (c -> d) -> p b c -> p a d
- lmap :: Profunctor p => (a -> b) -> p b c -> p a c
- rmap :: Profunctor p => (b -> c) -> p a b -> p a c
- dimap id id = id
- lmap id = id
- rmap id = id
- dimap f g = lmap f . rmap g
- lmap f = dimap f id
- rmap f = dimap id f
# Remarks
Profunctors are, as described by the docs on Hackage, "a bifunctor where the first argument is contravariant and the second argument is covariant."
So what does this mean? Well, a bifunctor is like a normal functor, except that it has two parameters instead of one, each with its own fmap
-like function to map on it.
Being "covariant" means that the second argument to a profunctor is just like a normal functor: its mapping function (rmap
) has a type signature of Profunctor p => (b -> c) -> p a b -> p a c
. It just maps the function on the second argument.
Being "contravariant" makes the first argument a little weirder. Instead of mapping like a normal functor, its mapping function (lmap
) has a type signature of Profunctor p => (a -> b) -> p b c -> p a c
. This seemingly backward mapping makes most sense for inputs to a function: you would run a -> b
on the input, and then your other function, leaving the new input as a
.
Note: The naming for the normal, one argument functors is a little misleading: the Functor
typeclass (opens new window) implements "covariant" functors, while "contravariant" functors are implemented in the Contravariant
typeclass in Data.Functor.Contravariant
(opens new window), and previously the (misleadingly named) Cofunctor
typeclass in Data.Cofunctor
(opens new window).