What is a contravariant functor?

前端 未结 4 1706
半阙折子戏
半阙折子戏 2020-12-23 11:56

The type blows my mind:

class Contravariant (f :: * -> *) where
  contramap :: (a -> b) -> f b -> f a

Then I read this, but con

4条回答
  •  爱一瞬间的悲伤
    2020-12-23 12:03

    I know this answer won't be as deeply academic as the other ones, but it's simply based on the common implementations of contravariant you'll come across.

    First, a tip: Don't read the contraMap function type using the same mental metaphor for f as you do when reading the good ol' Functor's map.

    You know how you think:

    "a thing that contains (or produces) an t"

    ...when you read a type like f t?

    Well, you need to stop doing that, in this case.

    The Contravariant functor is "the dual" of the classic functor so, when you see f a in contraMap, you should think the "dual" metaphor:

    f t is a thing that CONSUMES a t

    Now contraMap's type should start to make sense:

    contraMap :: (a -> b) -> f b ...

    ...pause right there, and the type is perfectly sensible:

    1. A function that "produces" a b.
    2. A thing that "consumes" a b.

    First argument cooks the b. Second argument eats the b.

    Makes sense, right?

    Now finish writing the type:

    contraMap :: (a -> b) -> f b -> f a

    So in the end this thing must yield a "consumer of a".

    Well, surely we can build that, given that our first argument is a function that takes an a as input.

    A function (a -> b) should be a good building block for building a "consumer of a".

    So contraMap basically lets you create a new "consumer", like this (warning: made up symbols incoming):

    (takes a as input / produces b as output) ~~> (consumer of b)

    • On the left of my made up symbol: The first argument to contraMap (i.e. (a -> b)).
    • On the right: The second argument (i.e. f b).
    • The whole thing glued together: The final output of contraMap (a thing that knows how to consume an a, i.e. f a).

提交回复
热议问题