`Profunctor`

is a typeclass provided by the `profunctors`

package in `Data.Profunctor`

.

See the "Remarks" section for a full explanation.

- 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

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 implements "covariant" functors, while "contravariant" functors are implemented in the `Contravariant`

typeclass in `Data.Functor.Contravariant`

, and previously the (misleadingly named) `Cofunctor`

typeclass in `Data.Cofunctor`

.