Data.Contravariant
Consumers of values: functors that map over their input, not their output.
A Functor produces as and fmap transforms what comes out; a Contravariant consumes as and contramap adapts what goes in. The arrow flips: to turn a consumer of a into a consumer of b, supply a function from b to a. The two carriers here are the archetypes: a Predicate tests a value, a Comparison orders two, and both are adapted to a new type by projecting into the one they already understand, the way a sort by key adapts an ordering on keys to an ordering on records.
contramap takes a pure projection: the carrier stores the function inside a closure, so an effectful projection would smuggle its row into every later call site unseen. Opt-in: not in Base.
Types
Predicate
newtype Predicate(a) = MkPredicate((a) -> Bool)
A test on a single value.
Comparison
newtype Comparison(a) = MkComparison((a, a) -> Int)
A total ordering as a function: negative, zero, or positive, with the same convention as cmp.
Type Classes
Contravariant
class Contravariant(f)
contramap : ((b) -> a, f(a)) -> f(b)
A functor over input: contramap(id, c) is c, and contramap(g, contramap(h, c)) is contramap(\(x) -> h(g(x)), c) (note the composition flips).
Instances
contravariantPredicate
instance contravariantPredicate : Contravariant(Predicate)
contravariantComparison
instance contravariantComparison : Contravariant(Comparison)
Functions and Values
mk_predicate
mk_predicate : forall a. ((a) -> Bool) -> Data.Contravariant.Predicate(a)
Wrap a test as a Predicate.
run_predicate
run_predicate : forall a. (Data.Contravariant.Predicate(a), a) -> Bool
Apply a Predicate to a value.
let evens = contramap(\(s) -> str_len(s), mk_predicate(\(n) -> n % 2 == 0))
(run_predicate(evens, "hi"), run_predicate(evens, "hey"))
(true, false)
mk_comparison
mk_comparison : forall a. ((a, a) -> Int) -> Data.Contravariant.Comparison(a)
Wrap an ordering function as a Comparison.
run_comparison
run_comparison : forall a. (Data.Contravariant.Comparison(a), a, a) -> Int
Apply a Comparison to two values.
let by_len = contramap(\(s) -> str_len(s), ord_comparison())
(run_comparison(by_len, "hey", "hi"), run_comparison(by_len, "hi", "no"))
(1, 0)
ord_comparison
ord_comparison : forall a. () -> Data.Contravariant.Comparison(a) given Ord(a)
The ordering an Ord instance already carries, as a Comparison value that contramap can then re-aim at another type.