motleycrue
motleycrue

Reputation: 81

Haskell Read Integers from a file to a list

I have a simple text file with one line:

6 195 265 750 265 750 196

I have a function:

executeList :: Integer -> [Integer] -> [String]
executeList n x = [reverseAndAdd n i | i <- x]

That takes an integer, list of integer and returns an array of Strings.

What I want to do, is to read that text file to and [Integer] list and pass that to executeList function. Here is my code:

main = do  
    let list = []
    handle <- openFile "data.txt" ReadMode
    contents <- hGetContents handle
    let singlewords = words contents
        list = f singlewords
    print list
    hClose handle   
f :: [String] -> [Integer]
f = map read

I found it here: Haskell file reading

When I run 'main' I get this output: [6,195,265,750,265,750,196]

but when I try to pass it like this to executeList:

let list = main
executeList 0 list

I get this error:

<interactive>:103:15: error:
* Couldn't match expected type `[Integer]' with actual type `IO ()'
* In the second argument of `executeList', namely `list'
  In the expression: executeList 0 list
  In an equation for `it': it = executeList 0 list

If I check the type of that list, i get this:

list :: IO()

I looked up on the internet for how to transform IO() to [Integer] but found nothing useful. Maybe someone can show me the way to do that conversion?

Upvotes: 3

Views: 4321

Answers (1)

Rainbacon
Rainbacon

Reputation: 943

The short answer is that you can't transform IO() into [Integer].

It seems as though you are misunderstanding the IO monad. Most functions return a value. Functions with a return type of IO a instead return an I/O action that performs some sort I/O before returning a value of type a. In your case IO () is an I/O action that will return () which is just an empty tuple. When you are writing console programs like this that read in data and then print out some results you'll typically follow this pattern:

  1. Read input from file or command line
  2. Pass data to function for computation
  3. Print results

Your whole program will end up living inside of the IO monad. do is a notation that is a syntactic sugar for the bind operator >>=. This operator allows us to chain monadic computations together. The <- in your code extracts a value from a monad (in your case an IO action) and stores it in a variable. Lets take a look at the type signature of hGetContents. From GHCI we can learn that this function has a type of hGetContents :: Handle -> IO String It takes a Handle and returns an I/O action that returns a string. When you call contents <- hGetContents handle the program calls hGetContents with the file handle you specified and then extracts a string from the IO action that is returned and stores that string in the variable contents. So now you've read the input. After you've converted the numbers to actual integer types the next step is to call your function which is the simple call let data = executeList 0 list From there you can output you data with print data. It's important to keep in mind that the whole time you are in the IO monad. In the end your entire main function should look something like this:

main = do
    handle <- openFile "data.txt" ReadMode
    contents <- hGetContents handle
    let singlewords = words contents
        list = f singlewords
        data = executeList 0 list
    print data
    hClose handle   

f :: [String] -> [Integer]
f = map read

Upvotes: 2

Related Questions