This question already has answers here:
A Haskell function of type: IO String-> String
(4 answers)
Converting IO Int to Int
(3 answers)
Closed 23 days ago.
I have a text file with the following data:
3
7 4
2 4 6
8 5 9 3
I want to essentially extract this data and return it in the form:
["3", "7 4", "2 4 6", "8 5 9 3"]
I used readFile to get the entire file as a single string, and then used lines to parse the individual line based on the '\n' character. I tried doing this but the problem I'm getting is that readFile returns IO String, but I want String instead. Here's the code:
readLines :: FilePath -> [String]
readLines str = do
file <- readFile str
let list = lines (file :: String)
list
How do I deal with this problem?
The purpose of IO is to prevent you from extracting data from I/O operations. Instead, your function will also return an IO action that, when executed at runtime, will produce a list of values.
readLines :: FilePath -> IO [String]
readLines str = do
file <- readFile str
let list = lines (file :: String)
return list
or more simply, because IO (like any monad) is a functor,
readLines :: FilePath -> IO [String]
readLines str = lines <$> readFile str
Related
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?
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:
Read input from file or command line
Pass data to function for computation
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
This question already has answers here:
A Haskell function of type: IO String-> String
(4 answers)
Closed 9 years ago.
I have a function with signature read_F95_src :: String -> IO [String]. This function is used elsewhere and cannot be changed.
I am reading in source lines and associated with a label as such src_lines = read_F95_src templ_src_name, which compiles and runs fine.
The problem is that I now have a function which takes in [String], and no matter how I try, I can't figure out a way to get the [String] value from src_lines.
You don't "extract" a value from IO. Instead you lift the rest of your computation into IO using fmap. So
read_F95_src :: String -> IO [String]
doSomethingWithStringList :: [String] -> Whatever
fmap doSomethingWithStringList :: IO [String] -> IO Whatever
fmap doSomethingWithStringList . read_F95_src :: String -> IO Whatever
You should get used to this pattern because it's going to happen to you a lot when you use Haskell. For example, if you want to do something with the IO Whatever you'll have to use the same trick again!
let src_lines = read_F95_src templ_src_name
(ss::[String]) <- src_lines
{- do whatever with ss -}
Extract the [String] like this inside a do block:
some_function :: IO [String]
some_function = do
dat <- read_F95_src "some data" -- Now the dat will contain the [String]
-- Now do all your stuffs on dat and return whatever you want to.
return dat
Once you have extracted the dat inside the function, you can apply other functions on it according to your logic and finally return whatever you need to.
I have a homework to sort a numbers that are to extract from a file.
Simple File Format:
45673
57879
28392
54950
23280
...
So I want to extract [Int] and than to apply my sort-function radix to it.
I write in my file
readLines :: FilePath -> IO [String]
readLines = fmap lines . readFile
makeInteger :: [String] -> [Int]
makeInteger = map read
and then I write in the command line
radix (makeInteger (readlines("111.txt")))
and then I have, off course, problems with type conversion from IO String to String. I tried to write
makeInteger :: IO [String] -> [Int]
makeInteger = map read
but it also doesn't work.
How do I work with pure data outside the IO monad?
According to this, "the inability to "escape" from the monad is essential for monads like IO".
So you need to do something like:
readLines :: FilePath -> IO [String]
readLines = fmap lines . readFile
makeInteger :: [String] -> [Int]
makeInteger = map read
main = do
content <- readLines "111.txt"
return (radix $ makeInteger content)
This "takes the content out" of the IO monad, applies the function you want on it, then puts it back into the IO monad again.
While preparing the Frege equivalents for the Real-world Haskell code examples (chapter 2), I could not find the equivalent for
:type readFile
What would be the closest match?
It seems you will have to use openReader :: String -> IO BufferedReader function along with getLines :: BufferedReader -> IO [String] function. Then you can just combine the list of string into a single string.
Ok, I made this
readFile :: String -> IO [String]
readFile fileName = do
file <- openReader fileName
file.getLines
(This wouldn't be displayed nicely as a comment, so I made it an answer)
I have text file containing data like that:
13.
13.
[(1,2),(2,3),(4,5)].
And I want to read this into 3 variables in Haskell. But standard functions read this as strings, but considering I get rid of dot at the end myself is there any built-in parser function that will make Integer of "13" and [(Integer,Integer)] list out of [(1,2),(2,3),(4,5)] ?
Yes, it's called read:
let i = read "13" :: Integer
let ts = read "[(1,2),(2,3),(4,5)]" :: [(Integer, Integer)]
The example text file you gave has trailing spaces as well as the full stop, so merely cutting the last character doesn't work. Let's take just the digits, using:
import Data.Char (isDigit)
Why not have a data type to store the stuff from the file:
data MyStuff = MyStuff {firstNum :: Int,
secondNum:: Int,
intPairList :: [(Integer, Integer)]}
deriving (Show,Read)
Now we need to read the file, and then turn it into individual lines:
getMyStuff :: FilePath -> IO MyStuff
getMyStuff filename = do
rawdata <- readFile filename
let [i1,i2,list] = lines rawdata
return $ MyStuff (read $ takeWhile isDigit i1) (read $ takeWhile isDigit i2) (read $ init list)
The read function works with any data type that has a Read instance, and automatically produces data of the right type.
> getMyStuff "data.txt" >>= print
MyStuff {firstNum = 13, secondNum = 13, intPairList = [(1,2),(2,3),(4,5)]}
A better way
I'd be inclined to save myself a fair bit of work, and just write that data directly, so
writeMyStuff :: FilePath -> MyStuff -> IO ()
writeMyStuff filename somedata = writeFile filename (show somedata)
readMyStuff :: FilePath -> IO MyStuff
readMyStuff filename = fmap read (readFile filename)
(The fmap just applies the pure function read to the output of the readFile.)
> writeMyStuff "test.txt" MyStuff {firstNum=12,secondNum=42, intPairList=[(1,2),(3,4)]}
> readMyStuff "test.txt" >>= print
MyStuff {firstNum = 12, secondNum = 42, intPairList = [(1,2),(3,4)]}
You're far less likely to make little parsing or printing errors if you let the compiler sort it all out for you, it's less code, and simpler.
Haskell's strong types require you to know what you're getting. So let's forgo all error checking and optimization and assume that the file is always in the right format, you can do something like this:
data Entry = Number Integer
| List [(Integer, Integer)]
parseYourFile :: FilePath -> IO [Entry]
parseYourFile p = do
content <- readFile p
return $ parseYourFormat content
parseYourFormat :: String -> [Entry]
parseYourFormat data = map parseEntry $ lines data
parseEntry :: String -> Entry
parseEntry line = if head line == '['
then List $ read core
else Number $ read core
where core = init line
Or you could write a proper parser for it using one of the many combinator frameworks.