1

Short-and-sweet, I have a text file that looks like this:

ID1|ID2|DATE|SUM
0|0|20/03/2014|100.00
0|1|20/04/2014|99.00

I have a custom data type that looks like this:

data DBData = DBData { id1   :: Int
                     , id2   :: Int
                     , date  :: String
                     , sum   :: Int
                     } deriving (Eq, Read, Show)

How do I get this into that?

What I have been toying with so far is using something like this:

parseRow :: [String] -> DBData 
parseRow = let (id1:id2:date:sum) = (splitWhen (=='|')) s
                i = read id1
             in DBData {id1 = i}

But I can't seem to get the syntax right ...

related to my other post: https://stackoverflow.com/questions/25477554/using-splitwhen-to-split-string-by-delimiter-and-trying-to-figure-out-how-to-sto

1 Answer 1

4

In Haskell, all data constructors and concrete types must begin with a capital letter:

data DbData = DbData ...

Also, if you want to use the read method to read in something in a custom format like that, you must make a the data type an instance of Read:

instance Read DbData where
  read s = ...

Inside the instance definition you can define read as you would any other Haskell function.

Also, the proper let syntax (outside a do block) is

let binding = val
in
... body ...

When you create a data type, you (usually) make one or more constructors that you can use to make values of that type. Here is an example that is sort of similar to yours

data Example = Example { a :: Int
                       , b :: Char
                       , c :: String
                       }

We can make a value of type Example using the Example constructor (note that these don't need to have the same name):

exampleValue :: Example
example = Example 1 'z' "abcdef"
Sign up to request clarification or add additional context in comments.

10 Comments

Any chance you could take that a step further, but struggling for a while trying to figure out how to get the data populated, don't mind how ... this was just a suggestion. But I don't understand what you mean by needing an instance and I don't see how that would allow me to parse our the pieces I need .. nor how to use it after
@JSchwartz Right now, the best thing to do would be to ignore the Read instance stuff altogether and try to define a normal function that reads the data from in that format into the data type. Use the DbData data constructor to construct a value of that type using the data that you've read in.
@JSchwartz I added a little bit of information about using data constructors. That is the main thing that you are missing in your code other than the syntactic issues.
@JSchwartz Add an s to the argument list for parseRow and line i up with the ( in the line above it. let definitions need to be lined up in this way. Also, I'd suggest removing Read from the deriving list. It won't help you read it in this case and it might lead to confusion later. By the way, you don't need parentheses around splitWhen. You also don't need to individually name each result of read. You could just replace i with read id1 in the field initialization.
@JSchwartz s is undefined. You need to tell Haskell you want to name the argument s: parseRow s = .... Also, I suspect you want your function type to be String -> DBData. String is a synonym for [Char] (so it's the exact same as [Char]).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.