Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active January 8, 2024 16:42
Show Gist options
  • Save CMCDragonkai/5cce00f732fcac0ec026 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/5cce00f732fcac0ec026 to your computer and use it in GitHub Desktop.
Demonstrating Monomorphism Restriction #haskell

By default GHCi has NoMonomorphismRestriction, whereas GHC has MonomorphismRestriction. Furthermore GHCi does not load the extensions of the modules that it loads. All of this can be changed with the LANGUAGE pragma or by setting the extensions inside the GHCi shell.

NoMonomorphismRestriction generally means that GHCi will try to infer the most polymorphic types and type signatures possible. While MonomorphismRestriction means GHC will try to infer the most monomorphic types and type signatures possible. An interesting

It makes sense for GHCi to have NoMonomorphismRestriction, in order to improve the user experience of using GHCi, this way you don't have to type out as much type signatures in GHCi, as the inference engine attempts to infer polymorphic types. Note that the default presence of NoMonomorphismRestriction only applies to code typed directly into the GHCi shell, any code externally loaded (source file) by GHCi is still subject to MonomorphismRestriction by default like as if it were directly compiled or executed with runhaskell.

MonomorphismRestriction is useful inside GHC and in production environments for a variety of reasons. But I found an interesting problem that occurs when you don't have MonomorphismRestriction on:

(===) :: Eq a => Maybe a -> a -> Maybe a
Just l === r | l == r = Just l
_ === _ = Nothing
infixl 4 ===

result = Just 1 === Nothing

The above should be a type error. But without MonomorphismRestriction, GHC and GHCi would not catch the type error. It's because of how 1 is inferred to be polymorphic Num a => a, instead of just Integer.

To get around MonomorphismRestriction, you just have to type out your preferred type signature explicitly in the code.

{-# LANGUAGE MonomorphismRestriction #-}
num = 1
-- :t num
-- num :: Integer
{-# LANGUAGE NoMonomorphismRestriction #-}
num = 1
-- :t num
-- num :: Num a => a
{-# LANGUAGE NoMonomorphismRestriction #-}
fmap2 = (fmap . fmap)
-- :t fmap2
-- fmap2 :: (Functor f1, Functor f) => (a -> b) -> f (f1 a) -> f (f1 b)
-- Only with NoMonomorphismRestriction or an explicit type signature, does this work
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment