Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Read (no instance)

I am a Haskell beginner and have a weird question. Up until now everything has been going great, and I have been able to use Prelude read function normally. Now suddenly I have to constantly declare it's type in order to use it.

I always have to declare this or something similar in order to use it.

let r = read::String-> Int

I have tried restarting ghci thinking I have accidentally overloaded read but whenever I try using it normally as such

read "456"

I get the following error

No instance for (Read a0) arising from a use of `read'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Read () -- Defined in `GHC.Read'
  instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
  instance (Read a, Read b, Read c) => Read (a, b, c)
    -- Defined in `GHC.Read'
  ...plus 25 others
In the expression: read "456"
In an equation for `it': it = read "456"

Does anyone have any ideas what could be causing this and how to fix it?

like image 489
cr0atIAN Avatar asked Jul 17 '13 21:07

cr0atIAN


2 Answers

First, to solve your problem, you could specify the result you expect from read in one of a few ways:

First, by specifying the type of the result of the entire computation:

read "456" :: Int

Or by specifying the type of the function read:

(read :: String -> Int) "456"

To explain why this happens, the issue is that read is polymorphic in its result type. That is, there are many different read functions defined, and they are defined as part of a typeclass Read. The error gives you the explanation why:

Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Read () -- Defined in `GHC.Read'
  instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
  instance (Read a, Read b, Read c) => Read (a, b, c)
    -- Defined in `GHC.Read'
  ...plus 25 others

The Read typeclass is defined for many, many types, it says there are 28 instances defined in the error. It's defined for Int, and for Integer, and Double, and String, and countless others. And so in order for the compiler to know what instance of the typeclass to use, it needs to be able to infer that from the type of read that you specify. If you give it :: String -> Int, the compiler can figure it out.

To understand how this works, let's look at part of the type class for Read:

class Read a where
  read :: String -> a

So for a given type a, an instance of Read a must be defined in order for the function read to return a value of type a. So for Int, there is a definition for an instance of Read Int, and indeed there is in GHC-Read. That instance defines how read works. Unfortunately, the instance is rather obtuse and relies on other functions and other such things, but for the sake of completeness, here it is:

instance Read Int where
  readPrec     = readNumber convertInt
  readListPrec = readListPrecDefault
  readList     = readListDefault

But, the important thing to realize is that this instance means that read will work for Int. But shortly after, there's this instance:

instance Read Double where
  readPrec     = readNumber convertFrac
  readListPrec = readListPrecDefault
  readList     = readListDefault

Oh dear. So read works for Int and for Double!

The Haskell language ensures the compiler will, usually, try to infer a unique type for a value or fail. There are some odd exceptions to this with some extensions to the language in GHC, but you have to remember here that Haskell is trying to prevent you from shooting yourself in the foot. If you don't specify somehow the type you're expecting from read, then the compiler could infer any type, but that might not be valid. You wouldn't want your code to suddenly start reading in floating point Doubles or arbitrary precision Integers where you previously expected to read in an Int, right?

In this case, not specifying the type merely caused the compiler to give up, it couldn't definitively answer the question you asked it to, which is, "Which instance of Read do I use?" And Haskell compilers do not like guessing. One way to prevent it from guessing is to use a value in a way that is unambiguous later, or to define a function that uses read unambiguously. For example, this function can be used in your code to avoid having to type :: String -> Int:

readInt :: String -> Int
readInt = read

The compiler can figure out which instance of Read it needs to use there, and in your code if you do:

readInt "456"

The compiler will know that readInt has type String -> Int, and thus readInt "456" has type Int. Unambiguous, just like Haskell likes it.

Addendum

The syntax in GHCi is a bit different for defining things, so if you are using GHCi exclusively to play around with Haskell, I'd recommend you switch to loading .hs files and using the :r command to reload them. One problem with GHCi is that you have to define everything with "let" which will start to feel strange when you start writing programs, where top level definitions don't need that. Another problem is the monomorphism restriction which, frankly, is just kind of weird and quirky and it's not worth going into detail about it here.

Anyhow, the syntax for defining readInt above in GHCi is simple, though there are two ways (equivalent). You already know one, which is to do it like this:

let readInt = read :: String -> Int

The other way is to define a function and its type separately, which is more akin to how it is done in a regular .hs file:

let readInt :: String -> Int; readInt = read

Neither is idiomatic Haskell, but that's because GHCi imposes quirky limitations on writing code and multi-line entry is strange. You could do this:

:{
let readInt :: String -> Int;
    readInt = read
:}

And that will get you close to the idiomatic Haskell definition. GHCi will however correctly compile my initial example if you put it in an .hs file and use :load or specify the file with ghci ./somefile.hs.

like image 67
Aaron Friel Avatar answered Oct 21 '22 23:10

Aaron Friel


When you type

read "456"

at the prompt, ghci has no information to find out which type you want. Do you want an Int, a Bool, (), String, ...

You need to tell it,

read "456" :: Int

so that it knows.

In a real programme, usually there is context which determines the required type, then it can be inferred and you don't need to manually supply a type. At the prompt, there is no context to help the inference.

like image 31
Daniel Fischer Avatar answered Oct 21 '22 23:10

Daniel Fischer