Skip to content

GHC doesn't respect monomorphism restrictions for non-type-class-restricted values that are bound

Applicable in both 6.6.1 and 6.7.something.

This compiles as expected:

loop = read "foo"
int = show loop
req :: Int; req = loop

This fails to compile:

loop = undefined
int = show loop
req :: Int; req = loop

This compiles with -fmono-pat-binds (the default setting), but not with -fno-mono-pat-binds:

(loop) = undefined
int = show loop
req :: Int; req = loop

This compiles unless we use both -fno-mono-pat-binds and -fno-monomorphism-restriction, as expected:

(loop) = read "foo"
int = show loop
req :: Int; req = loop

loop=undefined versus loop=loop doesn't make any difference.

This compiles even with -fno-mono-pat-binds -fno-monomorphism-restriction. I don't understand how/why/how much 'case' makes a monomorphic binding:

x = case undefined of
      loop -> let int = show loop; req :: Int; req = loop in ()

Admittedly, this is an odd case where the Report's rationales for the M-R <http://haskell.org/onlinereport/decls.html#sect4.5.4> aren't exactly applicable. "Rule 1 prevents computations from being unexpectedly repeated" -without typeclasses, no computations will be repeated. "Rule 1 prevents ambiguity" -well, true, but not in the strong way described by that point in the Report.

Encountered in the following, and I only recently figured out why it was not working.

{-# OPTIONS_GHC -fglasgow-exts -cpp #-}
{-# LANGUAGE CPP #-}

import Data.Typeable

#ifdef __GLASGOW_HASKELL__
import GHC.Prim ( unsafeCoerce# )
#endif
#ifdef __NHC__
import NonStdUnsafeCoerce (unsafeCoerce)
#endif
#ifdef __HUGS__
import Hugs.IOExts (unsafeCoerce)
#endif
#ifdef __GLASGOW_HASKELL__
unsafeCoerce :: a -> b
unsafeCoerce = unsafeCoerce#
#endif

data Dy = forall a. Dy !a !TypeRep

fromDyM :: Typeable a => Dy -> Maybe a

-- compiles:
fromDyM (Dy a typeRep) =
  case unsafeCoerce a of
    unsafeResult | typeRep == typeOf unsafeResult -> Just unsafeResult
                 | otherwise                      -> Nothing

--fails to compile:
fromDyM (Dy a typeRep) = result
 where
  unsafeResult = unsafeCoerce a
--(unsafeResult) = unsafeCoerce a --works because of mono-pat-binds
--unsafeResult = unsafeCoerce a `asTypeOfMaybe` result --was my earlier "fix"
  result | typeRep == typeOf unsafeResult = Just unsafeResult
         | otherwise                      = Nothing

asTypeOfMaybe :: a -> Maybe a -> a
asTypeOfMaybe a b = a

Testing the above examples in Hugs seems to be useless because Hugs's monomorphism is totally broken (it tries to find the monomorphic type too early in a way that depends on what order the declarations are in).

Trac metadata
Trac field Value
Version 6.6.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system Unknown
Architecture Unknown
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information