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)
Related
Okay, I'm new to the Haskell community having come from Python and this is driving me crazy.
I have a text file looking something like:
"1.2
1.423
2.43".
I want to read this text file and store it as a list of doubles in list_var. So list_var = [1.2,1.423,2.43]. This list_var will be used further in the program.
I just don't seem to find an answer on how to do this, most answers can print out list_var, e.g. Haskell - Read a file containing numbers into a list but I need list_var further down the line!
I have tried:
get_coefficients :: String -> [Double]
get_coefficients file_1 = do
coefficients_fromfile <- readLines "test2.txt"
let coefficients = map readDouble coefficients_fromfile
return coefficients
which doesn't work, readLines is
readLines :: FilePath -> IO [String]
readLines = fmap lines . readFile
and readDouble is
readDouble :: String -> Double
readDouble = read
Thanks in advance!
Since you use return, your output is in a monad, in this case the IO monad. As the error message tells you, you should change this line:
get_coefficients :: String -> [Double]
To this:
get_coefficients :: String -> IO [Double]
This is because of a core principle of Haskell: referential transparency.
If you want to use the [Double] produced, you still have to keep it in an IO monad, like so:
main :: IO ()
main = do
-- This can be thought of as taking out values from the monad,
-- but requires the promise that it'll be put back into a monad later.
doubles <- get_coefficients "This argument does nothing, why?"
-- This prints the list of doubles. Note: it returns an IO (),
-- thus fufills the promise!
-- print :: Show a => a -> IO ()
print doubles
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.
This is my first Haskell attempt so my understanding is fairly limited. I wanted to write a very basic program to check if a file contains the word ERROR. I came up with the following which of course doesn't even compile.
import Text.Regex.Posix
containsErrorString :: String -> Bool
containsErrorString x = x =~ "ERROR" :: Bool
fileContainsErrorString fileName = do
s <- readFile fileName
containsErrorString s
Is this the right approach and if not what would be the correct way to accomplish this?
Thanks
A light rewrite
I suggest:
Use Text instead of String for any "serious" work.
If you don't need regex, don't use regex.
In code:
import Data.Text as T
containsErrorString :: Text -> Bool
containsErrorString = ("ERROR" `T.isInfixOf`)
fileContainsErrorString :: FilePath -> IO Bool
fileContainsErrorString = containsErrorString `fmap` T.readFile
-- Warning, code typed and not tested.
Your Code
There isn't anything wrong with your approach. The use of String remains common and perfectly acceptable for most uses. Your error is just that you forgot to return the result (you are in a monad, IO, and containsErrorString is a pure function).
Instead of:
containsErrorString s
you should have had:
return (containsErrorString s)
Main problem is in fact that fileContainsErrorString :: IO Bool,
but containsErrorString (s:: String) :: Bool.
So, you need to wrap containsErrorString into IO, for example use return :: Monad m => a -> m a
fileContainsErrorString fileName = do
s <- readFile fileName
return $ containsErrorString s
I'm trying to do some programming in Haskell. I'm trying to read a file and then put every line in the file in a list by using the line function. Here's the partial code:
file = "muh.rtr"
readTrack :: String -> Track
readTrack file =
do let defFile = readFile file
let fileLines = lines defFile
However, I keep getting this error:
Parser.hs:22:39:
Couldn't match expected type `String' with actual type `IO String'
In the first argument of `lines', namely `defFile'
In the expression: lines defFile
In an equation for `fileLines': fileLines = lines defFile
I have been searching the Internet for hours now hoping to find some answers somewhere but I've not been so lucky so far.
You probably wanted either something like this:
readTrack :: String -> IO Track
readTrack file = do defFile <- readFile file
let fileLines = lines defFile
-- etc....
...or something like this:
readTrack :: String -> IO Track
readTrack file = do fileLines <- liftM lines (readFile file)
-- etc....
But what you really should do is stop, go find an introduction to the language such as Learn You a Haskell, and spend some time reading it.
Feeding code consisting entirely of very simple errors into GHC and then posting the error message on Stack Overflow is not a good way to learn.
The type of readFile is
readFile :: FilePath -> IO String
so you need to use <- to bind the result, and your function has to return IO Track.
readTrack :: String -> IO Track
readTrack file =
do defFile <- readFile file
let fileLines = lines defFile
...
I suggest reading a good tutorial on IO in Haskell, for example the Input and Output chapter of Learn You a Haskell for Great Good!.
readFile return an IO string. That is, it is an IO computation that returns a string. This means that you need to use <- instead of let to "get" the string its returning.
readTrack file =
do
defFile <- readFile file
...
You can use let to bind things that are not IO computations, such as the return value of lines, that is a regular string.
readTrack file =
do
defFile <- readFile file
let fileLines = lines defFile
...
Finally, you need to return the value you might want to try something like
readTrack file =
do
defFile <- readFile file
let fileLines = lines defFile
fileLines --Doesn't actually work!
but unfortunately, since we are inside a "do" block and are trying to return a monadic computation, we need to send the fileLines back into the io monad (remember, out function returns IO [String], not String!
readTrack file =
do
defFile <- readFile file
let fileLines = lines defFile
return fileLines
Note that the "return" here is not a return statement as would normaly be found in most languages and it should not be used in your pure functions.
All this might seem like a lot at first. I would suggest you stick to pure functions (without input and output / monads) until until you get a better hang on the language.
You can't do it like that -- you've run into the IO monad. What you need to do is something like:
readTrack :: String -> IO Track
readTrack file = do
defFile <- readFile file
let fileLines = lines deffile
...
return whatever
Think of IO T values as statements (as opposed to expressions) with return type T. Because statements have side effects, but expressions don't, you can never turn a statement into an expression; the type system enforces this, which is why your type signature won't work.
Note the different assignment-like syntax in the do block: in this example, the foo <- bar is used for IO operations, while the let baz = quux syntax is used for purely functional evaluation. This is more fallout from using monadic I/O -- it makes more sense in the full generality of Haskell's polymorphic type system, but it's not necessarily bad to have a syntactic indicator of pure vs. side-effecting operations, either.
In general, it is good practice to try keeping most of your implementation in the purely functional realm: implement your pure computation with regular functional methods, then describe your I/O operations in the IO monad. It is a common novice mistake to write loops in the IO monad which would be more appropriate as list comprehensions or recursive functions.
If your function is supposed to have type readTrack :: String -> Track, are you sure the String is a filename? Perhaps it's data - if so, don't use readFile. Write some sample data and test using that, eg
sampleData = "2 3\n1 30 234 45\n1 2 32 4\n5 3 4 23"
(The other question on SO about this homework didn't use file IO. I'll not link to it because you're in a crisis and might be tempted to copy, and in any case if you refuse to learn haskell at least I'll force you to improve your StackOverflow search skills! :) )
In any case I think you'll get more marks by solving the String problem than by solving the IO problem.
Delay the readFile issue until you've got the pure version working, otherwise you might end up writing most of your code in the IO monad which would be much more complex than necessary.
One you have a pure function readTrack :: String -> Track, you can do
readTrackFrom :: FilePath -> IO Track
readTrackFrom filename = fmap readTrack (readFile filename)
Now, fmap :: Functor f => (a -> b) -> f a -> f b, so takes pure functions and lifts them to work in a different computational context like IO.
Since IO is a Functor (look it up tomorrow, not tonight), we're using it as the type (String -> Track) -> IO String -> IO Track. That's good because readTrack :: String -> Track and (readFile filename) :: IO String.
If you want to, you can then >>= print or >>= writeFile newfilename as you see fit.
Don't forget to add deriving Show after use data Track =..., but you don't need to if you're using type Track = .....