Basic haskell program to find a string inside a file - haskell

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

Related

Monad transformers with IO and Maybe

I am trying to stack up IO and Maybe monads but either I don't understand monad transformers well enough or this is not possible using transformers. Can some one help me understand this?
f :: String -> Maybe String
main :: IO ()
main = do
input <- getLine -- IO String
output <- f input -- Maybe String (Can't extract because it is IO do block)
writeFile "out.txt" output -- gives error because writeFile expects output :: String
In the above simplified example, I have a function f that returns a Maybe String and I would like to have a neat way of extracting this in the IO do block. I tried
f :: String -> MaybeT IO String
main :: IO ()
main = do
input <- getLine -- IO String
output <- runMaybeT (f input) -- Extracts output :: Maybe String instead of String
writeFile "out.txt" output -- gives error because writeFile expects output :: String
which lets me extract the Maybe String out in the second line of do block but I need to extract the string out of that. Is there a way to do this without using case?
Let's stick for a moment with your first snippet. If f input is a Maybe String, and you want to pass its result to writeFile "out.txt", which takes a String, you need to deal with the possibility of f input being Nothing. You don't have to literally use a case-statement. For instance:
maybe from the Prelude is case analysis packaged as a function;
fromMaybe from Data.Maybe lets you easily supply a default value, if that makes sense for your use case;
traverse_ and for_ from Data.Foldable could be used to silently ignore Nothing-ness:
for_ (f input) (writeFile "out.txt") -- Does nothing if `f input` is `Nothing`.
Still, no matter what you choose to do, it will involve handling Nothing somehow.
As for MaybeT, you don't really want monad transformers here. MaybeT IO is for when you want something like a Maybe computation but in which you can also include IO computations. If f :: String -> Maybe String already does what you want, you don't need to add an underlying IO layer to it.

Haskell: read a text file of doubles and assign a list containing them to a list variable

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

Transformation of (a -> IO b) to IO (a -> b)

I have several data types in an IO context like:
a :: IO String
b :: IO FilePath
c :: String -> IO String
I want to put them all together in one data object like:
data Configdata = Configdata String FilePath (String -> String)
So I don't have to get each value for its own out of the IO context, but just out of IO Configdata.
The critical point where I don't have a solution is how I can transform String -> IO String to IO (String -> String).
Hoogle doesn't give me any functions which are capable of doing this.
I am not sure if it's maybe even not possible, since the input of the function is possibly infinite.
Does someone have a solution or an explanation why it's not possible?
I know that using a list instead of a function is an option, but I would prefer using a function if possible.
Indeed this is not possible. Consider the function:
import Acme.Missiles
boo :: String -> IO String
boo "cute" = return "Who's a nice kitty?"
boo "evil" = launchMissiles >> return "HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo​͟ur eye͢s̸ ̛l̕ik͏e liq​uid pain"
Now, if it were possible to transform this to IO (String -> String), it would have to execute all possible IO actions for any input before returning the pure String -> String function. IOW, even if you only planned to use the function for kitten-watching purposes, it would entail nuclear holocaust.
Nevertheless, it may well be possible to do this for your specific application. In particular, if you know the function will only ever be called for a predetermined set of strings, you can pre-query them from IO and store the results in a map, which can then be indexed purely.
import qualified Data.Map as Map
puh :: IO (String -> String)
puh = fmap ((Map.!) . Map.fromList) . forM ["cute"] $ \q -> do
res <- boo q
return (q, res)
Of course, this may not be feasible performance-wise.

Invert Return Value of Type IO Bool

I have a function that returns the type IO Bool. I'd like to use this function as an argument to filterM, but what I actually want to do is to invert its output. I've tried something to the effect of (not . f), but not isn't hip to the IO vibe. How can I invert an IO Bool?
Here's a minimal working example:
#!/usr/bin/env runhaskell
{-# LANGUAGE UnicodeSyntax #-}
module Main where
import Prelude.Unicode
userEnteredStr ∷ String → IO Bool
userEnteredStr str = do
input ← getLine
return (input ≡ str)
-- doesn't work. How would I write this function?
--userDidntEnterStr ∷ String → IO Bool
--userDidntEnterStr str = not . userEnteredStr
main = do result ← userEnteredStr "y"
print result
Sorry if this is basic! I can't find a function on Hoogle with type IO Bool -> IO Bool and haven't found anything in my web searching.
For the record, "doesn't work" is not a very helpful error description :) Is it a syntax error? a type error? does it compile and typecheck, but return the wrong value? It's probably the most vague description of your problem possible...and is usually a really really big impairment/hurdle for anyone who wants to help you.
The main problem here is that you can't apply not to an IO Bool, because not only works on Bools. An IO Bool is not a Bool, nor does it "contain a Bool", so it's not surprising that it doesn't work. It's like trying to apply (* 2) to your dog. Your dog isn't a number!
But it seems like you know how to work with do notation and binding from IO, so maybe you can understand why this would work?
userDidntEnterStr :: String -> IO Bool
userDidntEnterStr str = do
didEnter <- userEnteredStr str
return (not didEnter)
Alternatively, you can also apply any (a -> b) to the result of an IO a to get a new IO b using fmap:
userDidntEnterStr :: String -> IO Bool
userDidntEnterStr str = fmap not (userEnteredStr str)

What is the Frege equivalent to Haskell "readFile"?

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)

Resources