Consider the following higherorder function which maps the argument function to each tuple element:
tupleF elemF (x, y) = (elemF x, elemF y)
Left to its own devices, the Haskell 98 compiler will infer this type for the tupleF
function:
tupleF :: (a -> b) -> (a, a) -> (b, b)
As elemF
is applied to x
and y
, the compiler assumes that x
and y
must be of the same type, hence the inferred tuple type (a,a)
. This allows us to do the following:
tupleF length ([1,2,3], [3,2,1]) tupleF show (1, 2) tupleF show (True, False)
However, we cannot do this:
tupleF show (True, 2) tupleF length ([True, False, False], [1, 2, 4])
RankNTypes allow us to enforce parametric polymorphism explicitly. We want tupleF
to accept a polymorphic function; in other words we want our function to have a "higher rank type", in this case Rank 2
:
{-# LANGUAGE Rank2Types #-} tupleF' :: (Show a1, Show a2) => (forall a . Show a => a -> b) -- elemF -> (a1, a2...