6.4.16. Impredicative polymorphism¶
-
ImpredicativeTypes
¶ Implies: RankNTypes
Since: 6.10.1 Allow impredicative polymorphic types.
In general, GHC will only instantiate a polymorphic function at a monomorphic type (one with no foralls). For example,
runST :: (forall s. ST s a) -> a
id :: forall b. b -> b
foo = id runST -- Rejected
The definition of foo
is rejected because one would have to
instantiate id
‘s type with b := (forall s. ST s a) -> a
, and
that is not allowed. Instantiating polymorphic type variables with
polymorphic types is called impredicative polymorphism.
GHC has extremely flaky support for impredicative polymorphism,
enabled with ImpredicativeTypes
. If it worked, this would mean
that you could call a polymorphic function at a polymorphic type, and
parameterise data structures over polymorphic types. For example:
f :: Maybe (forall a. [a] -> [a]) -> Maybe ([Int], [Char])
f (Just g) = Just (g [3], g "hello")
f Nothing = Nothing
Notice here that the Maybe
type is parameterised by the
polymorphic type (forall a. [a] -> [a])
. However the extension
should be considered highly experimental, and certainly un-supported.
You are welcome to try it, but please don’t rely on it working
consistently, or working the same in subsequent releases. See
this wiki page for more details.
If you want impredicative polymorphism, the main workaround is to use a
newtype wrapper. The id runST
example can be written using this
workaround like this:
runST :: (forall s. ST s a) -> a
id :: forall b. b -> b
newtype Wrap a = Wrap { unWrap :: (forall s. ST s a) -> a }
foo :: (forall s. ST s a) -> a
foo = unWrap (id (Wrap runST))
-- Here id is called at monomorphic type (Wrap a)