In the book Thinking with Types, 6.4 Continuation Monad
tells that the types a
and forall r. (a -> r) -> r
are isomorphic, which can be witnessed by the following functions:
cont :: a -> (forall r. (a -> r) -> r)
cont x = \f -> f x
unCont :: (forall r. (a -> r) -> r) -> a
unCont f = f id
In this book, it tells that any two types that have the same cardinality will always be isomorphic to one another. So I try to figure out the cardinality of the types a
and forall r. (a -> r) -> r
.
Suppose the cardinality of the type a
is |a|
. Then for the type forall r. (a -> r) -> r
, how to figure out its cardinality equals |a|
? The function type a -> b
has cardinality |b|^|a|
, i.e., |b|
to the power of |a|
, so forall r. (a -> r) -> r
has cardinality of |r|^(|r|^|a|)
. How can it be equal to |a|
?
I'm confused. Thanks for any tips!
The cardinality argument doesn't really work with polymorphic types (see @chi's answer).
But isomorphism itself can be intuitively explained like this:
The type forall r. (a -> r) -> r
means "if you give me a function that converts a
to r
, I can give you back an r
. Oh, and I can do this for any possible r
whatsoever"
The only way to fulfill such promise is by secretly having an a
in my hand.
Since I promise to do this for any possible r
, it means I can't know anything about r
itself, including how to construct a value of it. And the only thing I have available is the function a -> r
that you give me. And the only way to call such function is by giving it an a
.
This means that if I'm making such promise, I must already secretly have an a
behind my back.
For a more formal explanation, recall that "isomorphic" in plain terms means "can be unambiguously converted back and forth without losses". This is what the cardinality argument is getting at: if you have the same number of things, you can always arrange a pairing between them.
And in your question you already show the two conversions: cont
converts one way, unCont
converts the other. And you can trivially show that cont . unCont = unCont . cont = id
. Therefore the types are isomorphic.
While showing the existence of the two conversions is more formal, I find it's not always satisfactory for getting an intuition for how the two types are really "kinda the same thing", hence the intuitive explanation I gave above.