haskellmonomorphism-restriction

'Referencing' typeclass functions


I'm a beginner and I'm trying to use Hoed to trace Haskell evaluations, because maybe it will further help my learning process.

I saw in their examples code like this

isEven :: Int -> Bool
isEven = observe "isEven" isEven'
isEven' n = mod2 n == 0

I was thinking how could I observe in order to trace an instance defined function like >>= for example.

I wrote something like

bind' = observe "bind'" (>>=)

and of course I've got an error

* Ambiguous type variable 'm0' arising from a use of '>>='
  prevents the constraint '(Monad m0)' from being solved.
  Relevant bindings include
    bind' :: m0 a0 -> (a0 -> m0 b0) -> m0 b0 (bound at my.hs:46:1)
  Probable fix: use a type annotation to specify what 'm0' should be.
  These potential instances exist:
  ...

Should I / How could I use a type annotation in order to specify which Monad instance's (e.g. Reader, State etc.) >>= function


Solution

  • It looks like you have found the infamous MonomorphismRestriction. More info. The links do a great job of explaining what the MonomorphismRestriction is and how it works.

    You're not wrong to expect that writing bind' with no signature should "just work". However, sometimes the compiler needs a bit of help. In short, due to the MonomorphismRestriction, GHC tries to take the nominally polymorphic signature of bind' :: Monad m => m a -> (a -> m b) -> m b, and make it less polymorphic by instantiating some of the type variables.

    In your case, it looks like the compiler wants to make bind' only work for one specific Monad m. Without your real code, I can't say for sure, but consider this example:

    import Debug.Trace
    
    main :: IO ()
    main = (>>=) (return "hello") print
    
    bind' = trace "bind" (>>=)
    

    The compiler produces an error similar to yours: Ambiguous type variable m0

    However, if you use bind':

    import Debug.Trace
    
    main :: IO ()
    main = bind' (return "hello") print
    
    bind' = trace "bind" (>>=)
    

    no error! That's because GHC is inferring that m should be IO since bind' is used in the IO monad.

    Alternatively, you can tell GHC to turn off the MonomorphismRestriction:

    {-# LANGUAGE NoMonomorphismRestriction #-}
    
    import Debug.Trace
    
    main :: IO ()
    main = (>>=) (return "hello") print
    
    bind' = trace "bind" (>>=)
    

    and it compiles just fine!