Reputation: 81
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
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:
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