Monomorphism restriction

From HaskellWiki
Jump to: navigation, search

The "monomorphism restriction" is a counter-intuitive rule in Haskell type inference. If you forget to provide a type signature, sometimes this rule will fill the free type variables with specific types using "type defaulting" rules. The resulting type signature is always less polymorphic than you'd expect, so often this results in the compiler throwing type errors at you in situations where you expected it to infer a perfectly sane type for a polymorphic expression.

A simple example is plus = (+). Without an explicit signature for plus, the compiler will not infer the type (+) :: (Num a) => a -> a -> a for `plus`, but will apply defaulting rules to specify plus :: Integer -> Integer -> Integer. When applied to plus 3.5 2.7, GHCi will then produce the somewhat-misleading-looking error, No instance for (Fractional Integer) arising from the literal ‘3.5’.

The restriction is turned on by default in compiled modules, and turned off by default at the GHCi prompt (since GHC 7.8.1). You can override these defaults by using the MonomorphismRestriction and NoMonomorphismRestriction language pragmas.

The exact definition of the restriction is fairly technical; it can be found in section 4.5.5 of the Haskell 2010 Report. To a first approximation it means that you often cannot overload a function unless you provide an explicit type signature. In summary:

-- This yields f1 :: (Show x) => x -> String
f1 x = show x

-- But this doesn't. Instead, f2 :: () -> String
f2 = \x -> show x

-- ...but we can fix that with an explicit type signature.
f3 = \x -> show x

-- Similarly this produces () -> String
f4 = show

-- ...but this is allowed
f5 = show


The difference between the first and second version is that the first version binds x via a "function binding" (see section 4.4.3 of the Haskell 2010 Report), and is therefore unrestricted, but the second version does not. The reason why one is allowed and the other is not is that it's considered clear that sharing f1 will not share any computation, and less clear that sharing f2 will have the same effect. If this seems arbitrary, that's because it is. It is difficult to design an objective rule which disallows subjective unexpected behaviour. Some people are going to fall foul of the rule even though they're doing quite reasonable things.

The monomorphism restriction is probably the most annoying and controversial feature of Haskell's type system. All seem to agree that it is evil - it is commonly called "The Dreaded Monomorphism Restriction" - but whether or not it is considered a necessary evil depends on who you ask.


And consider the function:
f xs = (len,len)
       len = genericLength xs

(This introductory section slightly expanded and re-arranged by YitzGale.)






, not



--Dainichi 06:53 15 Aug 2011 (UTC)

The following compiles for me on ghc 7.4.1:

module Main where
import Data.List

main = putStrLn $ show (f [])

f xs = (len,len)
       len = genericLength xs

If i add f2 = \x -> show x, compilation fails, demonstrating that i still have the monomorphism restriction enabled.

This is not due to type inference from the putStrLn $ show (f []) doing anything; in fact, this compiles fine:

module Main where
import Data.List

main = putStrLn ""

f xs = (len,len)
       len = genericLength xs

-- f2 = \x -> show x

whereas this fails to compile:

module Main where
import Data.List

main = putStrLn ""

--f xs = (len,len)
--     where
--       len = genericLength xs

f2 = \x -> show x

Why does the example from History of Haskell not fail? -- BayleShanks



See also: Section 4.5.5, Haskell 98 report.

-- Andrew Bromage


let f x = y  -- function definition
let F x = y  -- data structure decomposition


let x = y  -- function or pattern binding?

So, what speaks against differentiating the assignments notationally, say

let f x  = y  -- function definition
let F x <= y  -- data structure decomposition

and keep the monomorphism restriction as it is?

-- Henning Thielemann




- Cale Gibbard


  • GHC Trac bug 1749
  • In trying to build an editor with undoable actions:
class EditAction e a | e -> a where
  apply :: a -> e -> a

data ListAction a = Append a | Remove

instance EditAction (ListAction a) [a] where
  apply list (Append a) = a:list
  apply (x:xs) Remove = xs

-- Apply all the EditActions to the input
edit = foldl apply

Back before forM was in the Control.Monad library, I once spent about 1/2 an hour trying to figure out why my action in the ST monad was having its 's' parameter squished to (). I tore the code apart for quite a while before discovering that it was that the MR was applying to my definition of forM:

forM = flip mapM

I recently got tired of typing print "blah" in a ghci shell session and tried let p = print. Thanks to MR and Haskell defaulting, the type of p silently became () -> IO (). No surprise that my new "short" version of print was only capable of printing void values -

Prelude> p () () Prelude> p "blah" <interactive>:1:2: Couldn't match expected type `()' against inferred type `[Char]' In the first argument of `p', namely `"blah"' In the expression: p "blah" In the definition of `it': it = p "blah"

import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade

xmlGetWidget' = xmlGetWidget undefined

main :: IO ()
  = do
    window <- xmlGetWidget' castToWindow "window1"
    button <- xmlGetWidget' castToButton "button1"
    widgetShowAll window




I wasn't expecting the following to fail...

square x = x * x 
dx = 0.0000001

and for this to work.

square x = x * x 
dx = 0.0000001

The fix was to add

dx :: Fractional a => a



I tried to define foldl in terms of foldr, and discovered

foldl' = foldr (\x y -> (\a h -> y (h a x) h)) const

doesn't typecheck while

foldl' xs v f = foldr (\x y -> (\a h -> y (h a x) h)) const xs v f

does. Spent a solid couple hours trying to find where my derivation went wrong before accidentally stumbled upon the solution. -- wzy