Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating instance of Read type class in Haskell for custom data type

I have a custom data type Foo = Foo{ a :: Int, b :: Int} and I'm trying to make Foo a custom instance of read. I already have a function bar :: String -> Foo and I tried doing this:

instance Read (Foo a b) where
    read s = bar s

but I'm getting the following error when I load my file into GHCi to test it: Fraction.hs:11:1: read' is not a (visible) method of class Read'

Could someone tell me what the problem is and how I can actually instantiate this type?

like image 728
njvb Avatar asked Apr 02 '11 03:04

njvb


People also ask

What is an instance of a Haskell type class?

An instance of a class is an individual object which belongs to that class. In Haskell, the class system is (roughly speaking) a way to group similar types. (This is the reason we call them "type classes"). An instance of a class is an individual type which belongs to that class.

What are type classes in Haskell What purpose do they serve?

In Haskell, type classes provide a structured way to control ad hoc polymorphism, or overloading. [For the stylistic reason we discussed in Section 3.1, we have chosen to define elem in infix form. == and || are the infix operators for equality and logical or, respectively.]

What is the difference between type and data in Haskell?

Type and data type refer to exactly the same concept. The Haskell keywords type and data are different, though: data allows you to introduce a new algebraic data type, while type just makes a type synonym. See the Haskell wiki for details.


2 Answers

The Read typeclass doesn't declare read directly; instead, it defines readsPrec, which supports precedence (this is important when reading a value of a complex data type involving elements of other types). The definition you get when you use deriving (Read) looks roughly like

instance (Read a) => Read (Tree a) where

    readsPrec d r =  readParen (d > app_prec)
                     (\r -> [(Leaf m,t) |
                             ("Leaf",s) <- lex r,
                             (m,t) <- readsPrec (app_prec+1) s]) r
                  ++ readParen (d > up_prec)
                     (\r -> [(u:^:v,w) |
                             (u,s) <- readsPrec (up_prec+1) r,
                             (":^:",t) <- lex s,
                             (v,w) <- readsPrec (up_prec+1) t]) r
      where app_prec = 10
            up_prec = 5

(this obviously for a Tree data type, but similar rules apply for other user-defined ADTs). (Also, the above is a slight lie: GHC actually uses a different implementation, but the above is the kind of thing you should do unless you're willing to dig around inside of GHC.)

read is defined in terms of readsPrec and readList (the other method in Read, which is defaulted for every type except Char where it's used to read [Char] as a string instead of as a list of Char).

If the standard derivation isn't sufficient, for a type like yours that is simply a bucket of Ints you can ignore the precedence parameter.

BTW, Read and Show are rather slow; you may want to consider other ways to do I/O with your data.

like image 79
geekosaur Avatar answered Oct 18 '22 00:10

geekosaur


That's because the class method that you'd probably want to implement is readsPrec. See here for complete info on Read typeclass: http://zvon.org/other/haskell/Outputprelude/Read_c.html

BTW, you should be able to just use automatic derivation and the compiler will instantiate those Read methods for you e.g.:

data Foo = Foo Int Int
           deriving (Read, Show)
like image 3
ryaner Avatar answered Oct 17 '22 23:10

ryaner