2 ms·
Contravariance, as shown here, is extremely helpful for a working programmer and (like much of strongly typed functional programming) becomes more so as you beg
by clhodapp 8y ago
Contravariance, as shown here, is extremely helpful for a working programmer and (like much of strongly typed functional programming) becomes more so as you begin to let go of that type of concern and just learn the stuff.
Say you have a JSON encoder that knows how to turn Strings into JSON. You can make an encoder for UUIDs with that encoder and a simple contramap operation.
In Scala:
// First, summon a String encoder
val stringEncoder: Encoder[String] = Encoder[String]
// Now contramap
val uuidEncoder: Encoder[UUID] =
stringEncoder.contramap[UUID](_.toString)
Of course, you're free to do this inline so there's not usually so much val-binding involved.
- evincarofautumn 8y agoProfunctors are another great example of variance in functional programming. A profunctor is a type constructor that takes two arguments, one contravariant, one covariant. The simplest example of this is the function type constructor (->): you can lmap (contramap) the first type parameter by composing a function before the input, or rmap (fmap) the second type parameter by composing a function after the result: pipe :: A -> B lmap (modifyInput :: A' -> A ) pipe :: A' -> B rmap (modifyOutput :: B -> B') pipe :: A -> B' Profunctors are the class of types that behave like functions or “pipes”—anything that takes input of some type and produces output of another type, which you want to be able to stitch together in a pipeline. In fact I think the only way to have a contravariant type parameter in Haskell is to use it on the left of a function arrow, or not use it at all; all Profunctor instances are wrappers for something function-like.