Before reading this typeclass, we recommend that you understand Contravariance first. But, for making things easier, we will consider Contravariance
as the ability to flip composition.
Profunctors
are Bifunctors
that are contravariant in their first argument and covariant in the second one.
The core operation of the Profunctor
typeclass is dimap
(as bimap
was already taken for Bifunctor
).
fun <A, B, C, D> Kind2<F, A, B>.dimap(fl: (C) -> A, fr: (B) -> D): Kind2<F, C, D>
The main difference between bimap
and dimap
is the function they accept as their first argument:
bimap
: fl: (A) -> C
dimap
: fl: (C) -> A
And how does this work? Well, if we think in terms of function composition, functions can be composed in both directions:
import arrow.core.*
val sum2: (Int) -> Int = { x -> x + 2 }
val str: (Int) -> String = { x -> x.toString() }
val f = str compose sum2
val g = sum2 andThen str
f(4) == g(4)
// true
So, if we have a function (A) -> B
and a Profunctor
instance for it, we can make the following transformation with dimap
: ((C) -> A) -> ((A) -> B) -> ((B) -> D)
.
Contramap on the first type parameter and map on the second type parameter.
fun Kind2<F, A, B>.dimap(fl: (C) -> A, fr: (B) -> D): Kind2<F, C, D>
For a full list of other useful combinators available in Profunctor
, see the Source
Arrow provides ProfunctorLaws
in the form of test cases for internal verification of lawful instances and third party apps creating their own Profunctor instances.
Do you like Arrow?
✖