1

I have been trying to a read file creating data in haskell. i have the following data type constructed:

data Participant = Participant {name:: String, age:: Int,
                                country:: String, }

The text file i have is in this format

Jack 21 England
Natalie 20 France
Sophie 24 France

Each word corresponds to name age and country respectivly. I want to read the file and create a list of participants. But IO:String seem to be a pain in the neck. Do you have a suitable soliton for this problem.

2
  • 1
    What have you tried, specifically? Where did the problem lie? Commented Jun 8, 2020 at 16:15
  • 3
    My suitable solution is: get a neck massage. Then use your IO String. Commented Jun 8, 2020 at 19:05

2 Answers 2

2

IO isolation is not a defect, but a feature of Haskell, and one of its clear success.

If you want to serialize data to file, and load data back into your program, you don't have to do that by hand. Use any serializing library, there are many of them. You can also use the great Aeson library, that can convert your data in JSON and load them back.

If you want to do that by hand for any reason, you must first define your own file format, and have it unambiguous. For example, what happens on your example if name contains a space ?

Then you should define a function that can parse one line of your file format and produce a Participant readParticipant :: String -> Maybe Participant. Notice the maybe, because if the string is ill-formated, your function won't be able to create a participant out of its hat, so it will produce a Nothing.

Then you can have a function that parse a list of participants (notice the plural) readParticipants :: String -> [Participants]. No Maybe here because the list itself allows for failure.

Now you can have a tiny IO function that will read the file content, and run readParticipants on it.

readParticipantsIO :: IO [Participants]
readParticipantsIO = readParticipants <$> readFile "participants.data"

-- alternative definition, exact same behaviour in this case

readParticipantsIO :: IO [Participants]
readParticipantsIO = do
  content <- readFile "participants.data"
  return $ readParticipants content

Sign up to request clarification or add additional context in comments.

Comments

1

The lines and words functions can be used to split the string into a list of strings, and then you can package these strings into a list of Participant.

import Text.Read (readMaybe)

data Participant = Participant { name :: String, age :: Int, country :: String }

parseParticipants :: String -> [Participant]
parseParticipants fileContents = do
    [name', age', country'] <- words <$> lines fileContents
    Just age'' <- return (readMaybe age')
    return (Participant { name = name', age = age'', country = country' })

main :: IO ()
main = do
    participants <- parseParticipants <$> readFile "yourfile.txt"
    -- do things with the participants
    return ()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.