3
votes
main = do  
    putStrLn $myLast [1,2,3,4]

myLast :: [a] -> a
myLast [x] = x
myLast (_:xs) = myLast xs

When i try to run this code i get this message:

"No instance for (Num String) arising from the literal `1' Possible fix: add an instance declaration for (Num String)"

It runs well when I run with the list ["1","2","3,"4"]. I didn't specify the type but it doesn't work with ints.

3
This is just another way to say that a number is not a string, and putStrLn badly wants a String.Ingo

3 Answers

14
votes

"No instance for..." error messages are usually misleading.

The problem you have is simply this

Prelude> :t putStrLn
putStrLn :: String -> IO ()

i.e. that function can only deal with strings, not with numbers. An often-seen solution is to first translate the thing you want to show into a string: putStrLn (show x), but actually the combination exists as a much nicer standard function:

main = do  
    print $ myLast [1,2,3,4]
6
votes

The compiler concludes from

putStrLn x

that x must be a String. The inferred type for

myLast [1,2,3,4]

is Num a => a and when you now substitute a with String you get

Num String => String

This is all quite logical, except that the type checker remembers that the Num constraint originated from the literal 1.

The message you get is thus just another way to say that a number is not a string, and putStrLn badly wants a string. Or, if you want, that the expression would be well typed, if only strings were numbers.

1
votes

putStrLn has type String -> IO () so you need to convert your list element into a string first.

You can do this with show:

putStrLn $ show $ myLast [1,2,3,4]