15
votes

I'm trying to pull a value out of a monad, but keep the value, which doesn't depend on the monad, polymorphic. Specifically:

foo :: (Monad mon, Ring a) => mon a
foo = return 3

main :: IO ()
main = do
  x <- foo
  print (x :: Double)
  print (x :: Int)

The point is that the monadic portion of the computation is expensive to compute, so I only want to do it once, while keeping the value in the monad polymorphic. All of my attempts so far:

  1. giving x the signature forall a. (Ring a) => a)
  2. giving foo :: (Monad mon) => mon (forall a . (Ring a) => a)
  3. enabling -XNoMonomorphismRestriction and NoMonoLocalBins

have either not worked or given errors about impredicative polymorphism, which I'm not willing to use. Is there some way to pull a polymorphic value out of a monad without impredicative polymorphism (or alternatively: is there a safe way to use impredicative polymorphism in GHC)?

2

2 Answers

23
votes

You can work around the absence of impredicative polymorphism by wrapping the polymorphic value in a special data type.

newtype AnyRing = AnyRing (forall a. Ring a => a)

foo :: Monad m => m AnyRing

main = do
  AnyRing x <- foo
  print (x :: Double)
  print (x :: Int)
4
votes

I found another interesting solution, which came from this paper on typed, tagless, final interpreters (section 2.3).

The idea is to use a "duplicator":

data Dup a b = Dup a b

duplicate :: Dup a b -> (a,b)
duplicate (Dup a b) = (a,b)

instance (Num a, Num b) => Num (Dup a b) where
  fromInteger x = Dup (fromInteger x) (fromInteger x)
  ...

foo :: (Monad mon, Num a) => mon a
foo = return 3

main :: IO ()
main = do
 x <- foo
 let (y,z) = duplicate x
 print (y :: Double)
 print (z :: Int)

This solution isn't as general as Li-yao Xia's (it only works when the monadic value is an instance of a type class), but it is interesting because you don't need higher-rank polymorphism.