1

The following code

import Control.Applicative
import Control.Arrow
import Data.List.Split

main :: IO ()
main = do
    ints <- getNumberLine
    integers <- getNumberLine
    print $ foo ints integers

getNumberLine = readDataLine <$> getLine

readDataLine :: Read a => String -> [a]
readDataLine = splitOn " " >>> map read

foo :: [Int] -> [Integer] -> String
foo _ _ = "hello"

gives this error message:

GetNumberLine.hs:9:22:
    Couldn't match type `Int' with `Integer'
    Expected type: [Integer]
      Actual type: [Int]
    In the second argument of `foo', namely `integers'
    In the second argument of `($)', namely `foo ints integers'
    In a stmt of a 'do' block: print $ foo ints integers
Failed, modules loaded: none.

It only works if I create a second getNumberLine function:

import Control.Applicative
import Control.Arrow
import Data.List.Split

main :: IO ()
main = do
    ints <- getNumberLine
    integers <- getNumberLine2
    print $ foo ints integers

getNumberLine = readDataLine <$> getLine
getNumberLine2 = readDataLine <$> getLine

readDataLine :: Read a => String -> [a]
readDataLine = splitOn " " >>> map read

foo :: [Int] -> [Integer] -> String
foo _ _ = "hello"

which I find quite ugly.

Why is this necessary? And is there a better way?

Tobias Hermann
  • 9,936
  • 6
  • 61
  • 134

1 Answers1

5

You have been bitten by the Dreaded monomorphism restriction. The simplest fix is to add a type signature to your function:

getNumberLine :: Read a => IO [a]
getNumberLine = readDataLine <$> getLine

See here for some previous SO discussion.

Community
  • 1
  • 1
Ørjan Johansen
  • 18,119
  • 3
  • 43
  • 53