"read"-ing string data into haskell "data" types
Thanks to this excellent tutorial, I know how to read a string (in this case read from a file at people.txt
directly into a type synonym:
type Person = [Int]
like this:
people_text <- readFile "people.txt"
let people :: [Person]
people = read people_text
What I want to do is use a datatype (instead of a type synonym).
Any pointers on what I am missing here? I thought I would be able to read string-data directly into a Pe开发者_运维技巧rson
- defined like this (credit to learnyouahaskell.com)
data Person = Person String String Int Float String String deriving (Show)
When I try the obvious
txt <- readFile "t.txt" (this works OK)
with t.txt
containing
"Buddy" "Finklestein" 43 184.2 "526-2928" "Chocolate"
I get this error:
No instance for
(Read Person)
First of all, you need to derive Read
for your type.
You can think of read
and show
as being opposites, and a sort of poor man's serialization. show
lets you convert to String
, read
converts from String
, and in most cases the String
produced should also be valid Haskell code that, when compiled, produces the same value that read
gives you.
On that note, the contents of your file aren't going to work, because that's not the format used by the default implementations of read
and show
, i.e. the implementations you get by putting Read
and Show
in the deriving
clause.
For example, given this:
data Person = Person String String Int Float String String deriving (Read, Show)
buddy = Person "Buddy" "Finklestein" 43 184.2 "526-2928" "Chocolate"
Then in GHCi, we get:
> show buddy
"Person \"Buddy\" \"Finklestein\" 43 184.2 \"526-2928\" \"Chocolate\""
The quotes are escaped because that's a String
value. In the file, it would look like this:
Person "Buddy" "Finklestein" 43 184.2 "526-2928" "Chocolate"
Which you'll note is the same as the original definition in the source file.
Just add Read
to the deriving
data Person = Person String String Int Float String String deriving (Show, Read)
"Read" is a typeclass, which means that it makes sense to have a function read :: String -> Person
. You can add "read" to the deriving statement, which will automatically generate something sensible for that read
function. Note that it would actually require putting "Person" before the various fields ("Buddy", etc).
Alternatively, you could define your own read function:
instance Read Person where
read str = undefined -- add your definition here
精彩评论