Safe Haskell | None |
---|---|

Language | Haskell2010 |

## Synopsis

- class Contravariant f => Divisible (f :: * -> *) where
- divided :: Divisible f => f a -> f b -> f (a, b)
- conquered :: Divisible f => f ()
- contrazip3 :: Divisible f => f a1 -> f a2 -> f a3 -> f (a1, a2, a3)
- contrazip4 :: Divisible f => f a1 -> f a2 -> f a3 -> f a4 -> f (a1, a2, a3, a4)
- contrazip5 :: Divisible f => f a1 -> f a2 -> f a3 -> f a4 -> f a5 -> f (a1, a2, a3, a4, a5)
- data Supplied (divisible :: * -> *) where

# Documentation

class Contravariant f => Divisible (f :: * -> *) where #

A `Divisible`

contravariant functor is the contravariant analogue of `Applicative`

.

Continuing the intuition that `Contravariant`

functors consume input, a `Divisible`

contravariant functor also has the ability to be composed "beside" another contravariant
functor.

Serializers provide a good example of `Divisible`

contravariant functors. To begin
let's start with the type of serializers for specific types:

newtype Serializer a = Serializer { runSerializer :: a -> ByteString }

This is a contravariant functor:

instance Contravariant Serializer where contramap f s = Serializer (runSerializer s . f)

That is, given a serializer for `a`

(`s :: Serializer a`

), and a way to turn
`b`

s into `a`

s (a mapping `f :: b -> a`

), we have a serializer for `b`

:
`contramap f s :: Serializer b`

.

Divisible gives us a way to combine two serializers that focus on different
parts of a structure. If we postulate the existance of two primitive
serializers - `string :: Serializer String`

and `int :: Serializer Int`

, we
would like to be able to combine these into a serializer for pairs of
`String`

s and `Int`

s. How can we do this? Simply run both serializer and
combine their output!

data StringAndInt = StringAndInt String Int stringAndInt :: Serializer StringAndInt stringAndInt = Serializer $ (StringAndInt s i) -> let sBytes = runSerializer string s iBytes = runSerializer int i in sBytes <> iBytes

`divide`

is a generalization by also taking a `contramap`

like function to
split any `a`

into a pair. This conveniently allows you to target fields of
a record, for instance, by extracting the values under two fields and
combining them into a tuple.

To complete the example, here is how to write `stringAndInt`

using a
`Divisible`

instance:

instance Divisible Serializer where conquer = Serializer (const mempty) divide toBC bSerializer cSerializer = Serializer $ a -> case toBC a of (b, c) -> let bBytes = runSerializer bSerializer b cBytes = runSerializer cSerializer c in bBytes <> cBytes stringAndInt :: Serializer StringAndInt stringAndInt = divide ((StringAndInt s i) -> (s, i)) string int

divide :: (a -> (b, c)) -> f b -> f c -> f a #

Conquer acts as an identity for combining `Divisible`

functors.

## Instances

contrazip3 :: Divisible f => f a1 -> f a2 -> f a3 -> f (a1, a2, a3) #

contrazip4 :: Divisible f => f a1 -> f a2 -> f a3 -> f a4 -> f (a1, a2, a3, a4) #

contrazip5 :: Divisible f => f a1 -> f a2 -> f a3 -> f a4 -> f a5 -> f (a1, a2, a3, a4, a5) #