Is it possible to write a Haskell function that yields a parameterised type where the exact type parameter is hidden? I.e. something like f :: T -> (exists a. U a)
? The obvious attempt:
{-# LANGUAGE ExistentialQuantification #-}
data D a = D a
data Wrap = forall a. Wrap (D a)
unwrap :: Wrap -> D a
unwrap (Wrap d) = d
fails to compile with:
Couldn't match type `a1' with `a'
`a1' is a rigid type variable bound by
a pattern with constructor
Wrap :: forall a. D a -> Wrap,
in an equation for `unwrap'
at test.hs:8:9
`a' is a rigid type variable bound by
the type signature for unwrap :: Wrap -> D a at test.hs:7:11
Expected type: D a
Actual type: D a1
In the expression: d
In an equation for `unwrap': unwrap (Wrap d) = d
I know this is a contrived example, but I'm curious if there is a way to convince GHC that I do not care for the exact type with which D
is parameterised, without introducing another existential wrapper type for the result of unwrap
.
To clarify, I do want type safety, but also would like to be able to apply a function dToString :: D a -> String
that does not care about a
(e.g. because it just extracts a String field from D
) to the result of unwrap
. I realise there are other ways of achieving it (e.g. defining wrapToString (Wrap d) = dToString d
) but I'm more interested in whether there is a fundamental reason why such hiding under existential is not permitted.
Yes, you can, but not in a straightforward way.
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
data D a = D a
data Wrap = forall a. Wrap (D a)
unwrap :: Wrap -> forall r. (forall a. D a -> r) -> r
unwrap (Wrap x) k = k x
test :: D a -> IO ()
test (D a) = putStrLn "Got a D something"
main = unwrap (Wrap (D 5)) test
You cannot return a D something_unknown
from your function, but you can extract it and immediately pass it to another function that accepts D a
, as shown.