cat/contravariant
Contravariant
functor type {minimal implementation - contramap
}.
Default implementations for: replace
, replace_flip
(>$ and $< operators).
Op type
, its Contravariant instance, and phantom
function.
Types
Contravariant
type in gleam.
// Haskell type class
class Contravariant f where
contramap :: (a -> b) -> f b -> f a
Contravariant laws:
- Preservation of
identity
: contramap id = id - Preservation of
composition
: contramap (g ∘ h) = (contramap h) ∘ (contramap g)
See functor type
for convention.
pub type Contravariant(f, a, b, fa, fb) {
Contravariant(contramap: fn(fn(a) -> b) -> fn(fb) -> fa)
}
Constructors
-
Contravariant(contramap: fn(fn(a) -> b) -> fn(fb) -> fa)
Type for reverse
functions.
type Op r a = a -> r
Examples
let o = Op(fn(x) { x % 2 == 1 })
o.apply(6)
// -> False
pub type Op(r, a) {
Op(apply: fn(a) -> r)
}
Constructors
-
Op(apply: fn(a) -> r)
Functions
pub fn op_contravariant() -> Contravariant(
OpC(a),
b,
c,
Op(a, b),
Op(a, c),
)
Op Contravariant Instance
.
// Haskell implementation
instance Contravariant (Op r) where
contramap :: (b -> a) -> Op r a -> Op r b
contramap f g = g∘. f
Examples
let f = fn(b) {
case b {
True -> 2
False -> 4
}
}
let original = Op(fn(x) { int.to_string(x * 2) })
let result = op_contravariant().contramap(f)(original)
result.apply(False)
// -> "8"
pub fn phantom(
functor: Functor(a, b, Nil, c, d),
contra: Contravariant(e, b, Nil, f, d),
) -> fn(c) -> f
Haskell phantom
function.
phantom :: (Functor f, Contravariant f) => f a => f b
phantom x = () <$ x $< ()
If f
is both Functor
and Contravariant
, it can’t use its argument in a meaningful way. The laws follow from the preservation of composition
for fmap
and contramap
.
Laws:
- fmap f = phantom
- contramap f = phantom
Examples
// Phantom type for the instance
pub type UnitF
// Construct two instances (functor and covariant) for the same type
let unit_functor: Functor(UnitF, _, _, _, Nil) =
Functor(fmap: fn(_) { cat.unit })
let unit_contravariant: Contravariant(UnitF, _, _, Nil, _) =
Contravariant(contramap: fn(_) { cat.unit })
// We are left with the instance UnitF
// According to the laws of composition for fmap and contramap, this type can't do anything
"abc"
|> phantom(unit_functor, unit_contravariant)
// -> Nil
pub fn replace(
contravar: Contravariant(a, b, c, d, e),
) -> fn(c, e) -> d
Haskell (>$)
operator.
(>$) :: b -> f b -> f a
(>$) = contramap ∘ const
Examples
let o = con.Op(int.to_string)
// Doesn't matter what value/type we send to the final apply
True
|> replace(op_contravariant())(7, o).apply
// -> "7"
pub fn replace_flip(
contravar: Contravariant(a, b, c, d, e),
) -> fn(e, c) -> d
Haskell ($<)
operator.
($<) :: f b -> b -> f a
($<) = flip(>$)
Examples
let o = con.Op(int.to_string)
// Doesn't matter what value/type we use for the final apply
[1, 2, 3]
|> replace_flip(op_contravariant())(o, 7).apply
// -> "7"