2

Consider the following two functions in Haskell (a minimal example of my real code):

printSequence :: (Show a, Show b) => a -> b -> IO ()
printSequence x y = (putStr . show) x >> (putStr . show) y

printSequence' :: (Show a, Show b) => a -> b -> IO ()
printSequence' x y = print' x >> print' y
    where print' = putStr . show

The first compiles fine, but the second produces the error:

 Could not deduce (a ~ b)
    from the context (Show a, Show b)
      bound by the type signature for
                 printSequence' :: (Show a, Show b) => a -> b -> IO ()
      at test.hs:8:19-53
      `a' is a rigid type variable bound by
          the type signature for
            printSequence' :: (Show a, Show b) => a -> b -> IO ()
          at test.hs:8:19
      `b' is a rigid type variable bound by
          the type signature for
            printSequence' :: (Show a, Show b) => a -> b -> IO ()
          at test.hs:8:19
    In the first argument of print', namely `y'
    In the second argument of `(>>)', namely `(print' y)'
    In the expression: (print' x) >> (print' y)

I understand this error to mean that GHC is requiring x and y to be of equivalent type. What I do not understand is WHY. Statements like print "fish" >> print 3.14 work perfectly fine in the interpreter, so why does GHC complain about x and y being different types when I call my print' function two separate times?

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
  • 1
    About the dreaded Monomorphism Restriction: http://stackoverflow.com/questions/32496864/what-is-the-monomorphism-restriction – chi Mar 06 '16 at 12:38

1 Answers1

1

add an explicit type signature:

printSequence' :: (Show a, Show b) => a -> b -> IO ()
printSequence' x y = print' x >> print' y
    where
    print' :: Show a => a -> IO ()
    print' = putStr . show

or use NoMonomorphismRestriction:

{-# LANGUAGE NoMonomorphismRestriction #-}

printSequence' :: (Show a, Show b) => a -> b -> IO ()
printSequence' x y = print' x >> print' y
    where
    print' = putStr . show

then,

\> printSequence' 5 "five"
5"five"
behzad.nouri
  • 74,723
  • 18
  • 126
  • 124
  • This works when copied verbatim, but I have a follow-up question regarding your first solution. Why does it fail when I provide the type signature in the same line, like `where print' = (putStr . show) :: Show a => a -> IO ()` ? – ApproachingDarknessFish Mar 06 '16 at 02:45
  • 1
    @ApproachingDarknessFish That's annotating the value on the right-hand side of the = sign, leaving GHC to infer the type of the name on the left-hand side. GHC infers monomorphic types for patterns without explicit function arguments, and declaring a polymorphic type on the right doesn't change that rule. – amalloy Mar 06 '16 at 05:35