[Haskell-cafe] Is this related to monomorphism restriction?

wren ng thornton wren at freegeek.org
Tue Dec 23 20:34:42 EST 2008


Maurí­cio wrote:
> Hi,
> 
> Why isn't the last line of this code allowed?
> 
> f :: (TestClass a) => a -> Integer
> f = const 1
> a = (f,f)
> g = fst a

Just to make explicit what other folks have brought up in passing. The 
real type of @f@ (that is without syntactic sugar) is:

     > f :: forall a. TestClass a => a -> Integer

Which in turn means that the type for @a@ is:

     > a :: ( (forall a. TestClass a => a -> Integer)
     >      , (forall a. TestClass a => a -> Integer) )

This signature isn't valid Haskell98 since it embeds the quantification 
and the contexts, but it's easily transformable into valid syntax.

     == {alpha conversion}
     > a :: ( (forall a. TestClass a => a -> Integer)
     >      , (forall b. TestClass b => b -> Integer) )
     == {scope extension, twice}
     > a :: forall a b. ( (TestClass a => a -> Integer)
     >                  , (TestClass b => b -> Integer) )
     == {context raising, twice}
     > a :: forall a b. (TestClass a, TestClass b) => ( (a -> Integer)
     >                                                , (b -> Integer) )
     == {invisible quantification sugar (optional)}
     > a :: (TestClass a, TestClass b) => ( (a -> Integer)
     >                                    , (b -> Integer) )

The alpha conversion, necessary before doing scope extension, is the 
step that might not have been apparent. Because @f@ is polymorphic in 
its argument, the different instances of @f@ can be polymorphic in 
different ways. This in turn is what leads to the ambiguity in @g@, 
monomorphism restriction aside.


If you wanted to have @a@ give the same types to both elements of the 
tuple, then you can use this expression instead:

     > a' = let f' = f in (f',f')

The important difference is that we're making the sharing explicit. This 
in turn means that, while @fst a'@ and @snd a'@ are still polymorphic, 
they can only be polymorphic in the same way. Hence,

     > a' :: forall a. TestClass a => ( (a -> Integer)
     >                                , (a -> Integer) )

This transformation is only looking at the type-variable sharing issue. 
It still runs afoul of the monomorphism restriction unless you resolve 
it in the ways others have mentioned.

-- 
Live well,
~wren


More information about the Haskell-Cafe mailing list