Any function (profunctor/category) has "inputs" and "outputs". First argument: input (contravariant), second argument: output (covariant). covariant argument.
π₯π¦ :: π₯ -> π¦
π¦π© :: π¦ -> π©
When composing, it works like domino pieces: πΊ >>> π = π»
the connecting parts must be match but prefer using colours for it.
π₯π¦ >>> π¦π© :: π₯ -> π©
The middle type has disappeared from the input/output interface of the function. π¦, as far as composition goes, is an existential type which is not reflected in the output.
(>>>) :: cat π₯ π¦ -> cat π¦ π© -> cat π₯ π©
If we want to modify the input and output of π₯π¦ :: π₯ -> π¦
, a natural pattern emerges: They are mapped at a different variance. What can compose on the left π₯? Anything that outputs π₯.
π₯'π₯ :: π₯' -> π₯
:: π₯ <- π₯'
And what about the right π¦? Anything that takes in π¦.
π¦π¦' :: π¦ -> π¦'
This natural observation demonstrates through child-like toys how contravariance emerges from the nature of composition.
π₯'π₯ >>> π₯π¦ >>> π¦π¦' :: π₯' -> π¦'
Here is how this observation is interprated as annotated functors.
,------------------- Op Hask :: Cat Type
| ,----------- Hask :: Cat Type
| | ,--- Hask :: Cat Type
| | |
(->) :: Type -> Type -> Type
with the mapping function
dimap :: (Ρn <- Ρn') -> (out -> out') -> ((Ρn -> out) -> (Ρn' -> out'))
dimap pre post f = pre >>> f >>> post
dimap :: (π₯ <- π₯') -> (π¦ -> π¦') -> ((π₯ -> π¦) -> (π₯' -> π¦'))
dimap π₯'π₯ π¦π¦' π₯π¦ = π₯'π₯ >>> π₯π¦ >>> π¦π¦'
And here is how it is interpreted for an arbitrary category cat :: Cat k
:
,------------- Op cat :: Cat k
| ,-------- cat :: Cat k
| | ,--- Hask :: Cat Type
| | |
cat :: k -> k -> Type
dimap :: Category cat => Op cat Ρn Ρn' -> cat out out' -> (cat Ρn out -> cat Ρn' out')
dimap (Op pre) post f = pre >>> f >>> post
Every category gives rise to a Profunctor { Input = cat, Output = cat }
using record syntax for associated types.
Profunctor { Input = cat, Output = cat }
= Bifunctor { Source1 = Op cat, Source2 = cat, Target = Hask }
= Functor { Source = Op cat, Target = Nat cat Hask }
dimap :: Profunctor { Input = input, Output = output } pro
-> Op input Ρn Ρn'
-> output out out'
-> (pro Ρn out -> pro Ρn' out')