catching errors during string parsing - haskell

I want to parse String to get Int and I use this:
string2int :: String -> Int
string2int str = read str::Int
Now I want to catch paring exception/error as SIMPLY as possible.
I tried:
import qualified Control.Exception as E
eVal <- try (print (string2int "a")) :: IO (Either E.SomeException ())
case eVal of
Left e -> do { putStrLn "exception"; }
Right n -> do { putStrLn "good"; }
But compiler says couldn't match expected type 'E.SomeException()'
with actual type E.IOException.
What am I doing wrong?
Ok I don't know how to use it for my problem: I want somthing like this:
loadfunction = do
{
x <- string2int getLine
if( failed parsing int ) call somefunction
y <- string2int getLine
if( failed parsing int ) call somefunction
otherfunction x y
}
I dont know how to do it using your answers...

You're using try imported from the old exceptions mechanism, but are trying to use its result type as if it was using the new extensible Control.Exception mechanism. Use E.try instead.
You should ideally import Control.Exception like this:
import Prelude hiding (catch)
import Control.Exception
and remove all imports of Control.OldException. Then you can use its functions directly without worrying about any clashes.
By the way, you don't have to use IO exceptions to handle read errors; you can use reads instead:
reads :: (Read a) => String -> [(a, String)]
Here's how I'd write your code with reads:
case reads "a" of
[(a, "")] -> do
print a
putStrLn "good"
_ -> putStrLn "exception"
The fact that reads returns a list is a little confusing; practically, you can think of it as returning Maybe (a, String) instead. If you want a version using Maybe, you can define it like this:
readMaybe :: (Read a) => String -> Maybe a
readMaybe s =
case reads s of
[(a, "")] -> Just a
_ -> Nothing
which makes your code become:
case readMaybe "a" of
Just a -> do
print a
putStrLn "good"
Nothing -> putStrLn "exception"
(You can also define readMaybe as listToMaybe . map fst . filter (null . snd) . reads like dave4420 did; they'll be equivalent in practice, since none of the standard Read instances ever return lists of more than one element.)
In general, you should try and use pure error-handling methods like this whenever possible, and only use IO exceptions when there's really no other option, or you're dealing with IO-specific code (like file/network handling, etc.). However, if you want to stick with exceptions, using E.try instead should fix your error.
Based on your updated question, however, exceptions might be the right way to go after all; something like ErrorT would also work, but if you're already doing everything in IO to start with, then there's no harm in using exceptions. So I would write your example like this:
loadfunction = do
line1 <- getLine
x <- string2int line1
line2 <- getLine
y <- string2int line2
otherfunction x y
and use E.catch to handle the exceptions it throws; take a look at the documentation for catch to see how to do that.

Related

How to correctly parse arguments with Haskell?

I'm trying to learn how to work with IO in Haskell by writing a function that, if there is a flag, will take a list of points from a file, and if there is no flag, it asks the user to enter them.
dispatch :: [String] -> IO ()
dispatch argList = do
if "file" `elem` argList
then do
let (path : otherArgs) = argList
points <- getPointsFile path
else
print "Enter a point in the format: x;y"
input <- getLine
if (input == "exit")
then do
print "The user inputted list:"
print $ reverse xs
else (inputStrings (input:xs))
if "help" `elem` argList
then help
else return ()
dispatch [] = return ()
dispatch _ = error "Error: invalid args"
getPointsFile :: String -> IO ([(Double, Double)])
getPointsFile path = do
handle <- openFile path ReadMode
contents <- hGetContents handle
let points_str = lines contents
let points = foldl (\l d -> l ++ [tuplify2 $ splitOn ";" d]) [] points_str
hClose handle
return points
I get this: do-notation in pattern Possibly caused by a missing 'do'?` after `if "file" `elem` argList.
I'm also worried about the binding issue, assuming that I have another flag that says which method will be used to process the points. Obviously it waits for points, but I don't know how to make points visible not only in if then else, constructs. In imperative languages I would write something like:
init points
if ... { points = a}
else points = b
some actions with points
How I can do something similar in Haskell?
Here's a fairly minimal example that I've done half a dozen times when I'm writing something quick and dirty, don't have a complicated argument structure, and so can't be bothered to do a proper job of setting up one of the usual command-line parsing libraries. It doesn't explain what went wrong with your approach -- there's an existing good answer there -- it's just an attempt to show what this kind of thing looks like when done idiomatically.
import System.Environment
import System.Exit
import System.IO
main :: IO ()
main = do
args <- getArgs
pts <- case args of
["--help"] -> usage stdout ExitSuccess
["--file", f] -> getPointsFile f
[] -> getPointsNoFile
_ -> usage stderr (ExitFailure 1)
print (frobnicate pts)
usage :: Handle -> ExitCode -> IO a
usage h c = do
nm <- getProgName
hPutStrLn h $ "Usage: " ++ nm ++ " [--file FILE]"
hPutStrLn h $ "Frobnicate the points in FILE, or from stdin if no file is supplied."
exitWith c
getPointsFile :: FilePath -> IO [(Double, Double)]
getPointsFile = {- ... -}
getPointsNoFile :: IO [(Double, Double)]
getPointsNoFile = {- ... -}
frobnicate :: [(Double, Double)] -> Double
frobnicate = {- ... -}
if in Haskell doesn't inherently have anything to do with control flow, it just switches between expressions. Which, in Haskell, happen to include do blocks of statements (if we want to call them that), but you still always need to make that explicit, i.e. you need to say both then do and else do if there are multiple statements in each branch.
Also, all the statements in a do block need to be indented to the same level. So in your case
if "file" `elem` argList
...
if "help" `elem` argList
Or alternatively, if the help check should only happen in the else branch, it needs to be indented to the statements in that do block.
Independent of all that, I would recommend to avoid parsing anything in an IO context. It is usually much less hassle and easier testable to first parse the strings into a pure data structure, which can then easily be processed by the part of the code that does IO. There are libraries like cmdargs and optparse-applicative that help with the parsing part.

Haskell - loop returning user input integer

I want to write a function which, when called, will relentlessly ask for user input until the input can be read as an integer, (at which point the integer is returned to a possible do block where the function was called in the first place)
My code here:
lp_reqInt =
do
input1 <- getLine
if ((readMaybe input1 :: Maybe Int) == Nothing)
then do
putStrLn "(integer input required, please try again)"
lp_reqInt
else let output = fromMaybe (-666) (readMaybe input1 :: Maybe Int)
return output
trying to compile this gives the suspiciously simple error of parse error (possibly incorrect indentation or mismatched brackets) for the last line. (No indent characters were used throughout the whole file)
How should I change my code to have the intended behaviour? Is that even possible?
The other answer discusses what was wrong, and the minimal fix. In addition to the minimal thing that will get you moving on with your code, I thought it might also be interesting to show the idiomatic fix, namely, to use pattern matching instead of if. So:
lp_reqInt :: IO Int
lp_reqInt = do
input1 <- getLine
case readMaybe input1 of
Nothing -> do
putStrLn "(integer input required, please try again)"
lp_reqInt
Just n -> return n
This doesn't require the use of the weird fall-back -666 in fromMaybe, which is nice. Using pattern matching instead of (==) also has a more subtle advantage: it doesn't require the underlying type to have an Eq instance. For Int there is one, so there's no advantage in this code, but in other situations it can matter more. I've also lifted the type signature to the top-level; see here for further discussion of this idiom.
You seem to be slightly misunderstanding how do-notation works.
I'll give you a 'correct' version and we can work off that:
lp_reqInt = do
input1 <- getLine
let maybeInput = readMaybe input1 :: Maybe Int
if maybeInput == Nothing
then do putStrLn "(integer input required, please try again)"
lp_reqInt
else return $ (\(Just x) -> x) maybeInput
Note the let-statement at the top there. I can do a let-statement rather than a let-in-statement here, because it is in the top level of a do-block. When you wrote let output = fromMaybe (...), that was not in the top level of a do-block, that was in the second part of an if-statement, hence it will not work.
You were getting a parse error for this very reason: GHC expected an accompanying in!
Previous answers are great but i just would like to extend this topic with another reasonable approach for those who end up here searching not exactly what the OP is asking for but something relevant.
Since the topic mentions User Input (IO) and Integer (Maybe Int) we end up with a type like IO (Maybe Int). Such types are best expressed under the Monad Transformers, namely MaybeT IO Int and they act nicely as Alternative class members as well.
Haskell has fantastic solutions for these cases such that we may approach the same problem like;
import Control.Monad (msum)
import Control.Monad.Trans.Maybe
import Control.Monad.Trans (lift)
import Text.Read (readMaybe)
lp_reqInt :: MaybeT IO Int
lp_reqInt = msum . repeat $ (lift . putStrLn) "Enter an integer.." >>
(MaybeT $ readMaybe <$> getLine)
It's relentless :)
λ> runMaybeT lp_reqInt
Enter an integer..
boru
Enter an integer..
not an integer
Enter an integer..
42
Just 42

Haskell: how to extract a value from a Right

I am building up a simple script to parse a two-items-per-row CSV file:
//Main.hs
module Main where
import qualified Data.ByteString.Lazy as BL
import qualified Data.Vector as V
import Data.Csv
type Row = (BL.ByteString, BL.ByteString)
main :: IO ()
main = do
csvData <- BL.readFile "csvs/twostringsperrow.csv"
let v = decode NoHeader csvData :: Either String (V.Vector Row)
putStrLn "All done"
The script works. Obviously it doesn't do much at the moment, but it works, which is reassuring.
I want to now interact with this in the GHCi and so I run those couple of lines:
$ stack ghci
...
*Main> csvData <- BL.readFile "csvs/twostringsperrow.csv"
*Main> let v = decode NoHeader csvData :: Either String (V.Vector Row)
*Main> v
Right [("1","2"),("3","4")]
At this point I can see that the parsing has been successful and would like to get the [("1","2"),("3","4")] out of the Right into a variable called df so that I can have a play with it. i.e.:
*Main> let df = <something here> v
*Main> df
[("1","2"),("3","4")]
How do I do that?
You can use pattern matching logic here. For example:
let Right df = v
We thus here unwrap the data out of Right data constructor.
You can for example write a function that handles both the Left and Right case, since it is typically better to implement total functions (functions that can process the entire space of values specified by the type).
A basic approach it to use a case.
do ...
x <- parse ...
case x of
Left e -> putStrLn ("Parse error" ++ show e)
Right y -> putStrLn ("Parse OK!" ++ show y)
Don't forget that we can not, in general, "remove a Right" in a safe way, since a value of type Either ParseError T is not necessarily a Right, but could also be a Left.
Indeed, the parsing library returns such a sum type in order to force us to handle the error, and consider both cases.
There are some dangerous partial functions that indeed "remove Right" but it is better to avoid them.

Idiomatic Haskell syntax without do-blocks or accumulating parentheses?

I'm fairly new to Haskell and have been trying to find a way to pass multiple IO-tainted values to a function to deal with a C library. Most people seem to use the <- operator inside a do block, like this:
g x y = x ++ y
interactiveConcat1 = do {x <- getLine;
y <- getLine;
putStrLn (g x y);
return ()}
This makes me feel like I'm doing C, except emacs can't auto-indent. I tried to write this in a more Lispy style:
interactiveConcat2 = getLine >>= (\x ->
getLine >>= (\y ->
putStrLn (g x y) >>
return () ))
That looks like a mess, and has a string of closed parentheses you have to count at the end (except again, emacs can reliably assist with this task in Lisp, but not in Haskell). Yet another way is to say
import Control.Applicative
interactiveConcat3 = return g <*> getLine <*> getLine >>= putStrLn
which looks pretty neat but isn't part of the base language.
Is there any less laborious notation for peeling values out of the IO taint boxes? Perhaps there is a cleaner way using a lift* or fmap? I hope it isn't too subjective to ask what is considered "idiomatic"?
Also, any tips for making emacs cooperate better than (Haskell Ind) mode would be greatly appreciated. Thanks!
John
Edit: I stumbled across https://wiki.haskell.org/Do_notation_considered_harmful and realized that the nested parentheses in the lambda chain I wrote is not necessary. However it seems the community (and ghc implementors) have embraced the Applicative-inspired style using , <*>, etc, which seems to make the code easier to read in spite of the headaches with figuring out operator precedence.
Note: This post is written in literate Haskell. You can save it as Main.lhs and try it in your GHCi.
A short remark first: you can get rid of the semicolons and the braces in do. Also, putStrLn has type IO (), so you don't need return ():
interactiveConcat1 = do
x <- getLine
y <- getLine
putStrLn $ g x y
We're going to work with IO, so importing Control.Applicative or Control.Monad will come in handy:
> module Main where
> import Control.Applicative
> -- Repeat your definition for completeness
> g :: [a] -> [a] -> [a]
> g = (++)
You're looking for something like this:
> interactiveConcat :: IO ()
> interactiveConcat = magic g getLine getLine >>= putStrLn
What type does magic need? It returns a IO String, takes a function that returns an String and takes usual Strings, and takes two IO Strings:
magic :: (String -> String -> String) -> IO String -> IO String -> IO String
We can probably generalize this type to
> magic :: (a -> b -> c) -> IO a -> IO b -> IO c
A quick hoogle search reveals that there are already two functions with almost that type: liftA2 from Control.Applicative and liftM2 from Control.Monad. They're defined for every Applicative and – in case of liftM2 – Monad. Since IO is an instance of both, you can choose either one:
> magic = liftA2
If you use GHC 7.10 or higher, you can also use <$> and <*> without import and write interactiveConcat as
interactiveConcat = g <$> getLine <*> getLine >>= putStrLn
For completeness, lets add a main so that we can easily check this functionality via runhaskell Main.lhs:
> main :: IO ()
> main = interactiveConcat
A simple check shows that it works as intended:
$ echo "Hello\nWorld" | runhaskell Main.lhs
HelloWorld
References
Applicative in the Typeclassopedia
The section "Some useful monadic functions" of LYAH's chapter "For a Few Monads More".
You can use liftA2 (or liftM2 from Control.Monad):
import Control.Applicative (liftA2)
liftA2 g getLine getLine >>= putStrLn

How to properly use the readMaybe function in IO

I started with programming in Haskell about 4 month ago and now I came to the point where I have to deal with the IO system of Haskell.
I already did a lot of IO actions and haven't faced any problems I couldn't solve by myself, but this time I googled for almost two hours for no avail to get some information about the function readMaybe. So I have the following problem set to solve and I already tried a lot of different approaches to solve it but all the time I get the same failure message from my compiler:
No instance for (Read a0) arising from a use of `readMaybe'
The type variable `a0' is ambiguous
I understand what the compiler does want to tell me but I have no idea how to solve this problem. I already tried to add a class constraint, but without success.
So here is my very small and simple program that is just counting how many valid numbers the user has entered. The program is meant to terminate when the user enters an empty line.
This is just a auxiliary function I want to use for my project later on.
countNumbers :: IO Int
countNumbers = do
x <- count 0
return x where
count :: Int -> IO Int
count n = do
line <- getLine
case line of
"" -> do
return n
_ -> case readMaybe line of
Just _ -> do
x <- count (n+1)
return x
Nothing -> do
x <- count n
return x
Unfortunately I couldn't find out a lot of informations about the function readMaybe. The only thing I could find was in the Haskell library Text.Read:
readMaybe :: Read a => String -> Maybe aSource
Parse a string using the Read instance. Succeeds if there is exactly one valid result.
The very weird thing for me is that I have already written such a function that uses the readMaybe function and it worked perfectly ...
This program is just asking the user for a number and keeps asking as long as the user enters a valid number
getLineInt :: IO Int
getLineInt = do
putStrLn "Please enter your guess"
line <- getLine
case readMaybe line of
Just x -> do
return x
Nothing -> do
putStrLn "Invalid number entered"
x <- getLineInt
return x
So far as I can see there are no differences between the usage of the function readMaybe in the two programs and therefore it works in the one but not in the other :)
I would be really thankful for any hints from you!!
This has nothing to do with IO, so maybe you don't understand what the compiler is trying to tell you. There is a type variable a in readMaybe's signature; a has to have a Read instance, but other than that it can be anything. The compiler is telling you that it doesn't have any way to determine what you want a to be.
In getLineInt you don't have this problem, because you are returning the result of readMaybe and the type signature says it should be Int. In countNumbers, you're not using the result of readMaybe, so there's nothing that can be used to determine the correct type. You can fix this by adding an explicit type signature (I picked Int since you're apparently counting numbers):
_ -> case readMaybe line :: Maybe Int of
Finally a word about do notation: it's just syntactic sugar, you don't have to use it all the time. Instead of do return x you can simply write return x, and instead of
x <- getLineInt
return x
you can simply do
getLineInt
That makes things more readable:
getLineInt :: IO Int
getLineInt = do
putStrLn "Please enter your guess"
line <- getLine
case readMaybe line of
Just x -> return x
Nothing -> putStrLn "Invalid number entered" >> getLineInt
Why does this happen?
In your second function, it is clear that readMaybe line is used as String -> Maybe Int, since type inference notices that you use return x and therefore x must be an Int.
In your first function, you don't use the Maybe's value at all, you just want to check whether the read succeeded. However, since you didn't specify the type (neither explicit nor implicit with type inference), the type variable is ambiguous:
_ -> case readMaybe line of
There's an easy fix: annotate the type:
_ -> case readMaybe line :: Maybe Int of
By the way, this is exactly the same behaviour you encounter when you use read in ghci without any type context:
> read "1234"
<interactive>:10:1:
No instance for (Read a0) arising from a use of `read'
The type variable `a0' is ambiguous
As soon as you make the type clear everything is fine:
> read "1234" :: Int
1234
Making things clear
Now that we've seen why the error happens, lets make this program much simpler. First of all, we're going to use a custom readMaybe:
readMaybeInt :: String -> Maybe Int
readMaybeInt = readMaybe
Now how does one count numbers? Numbers are those words, where readMaybeInt doesn't return Nothing:
countNumbers :: String -> Int
countNumbers = length . filter isJust . map readMaybeInt . words
How does one now calculate the numbers in the standard input? We simply take input until one line is completely empty, map countNumbers on all those lines and then sum:
lineNumberCount :: IO Int
lineNumberCount =
getContents >>= return . sum . map countNumbers . takeWhile (/= "") . lines
If you're not used to the bind methods, that's basically
lineNumberCount :: IO Int
lineNumberCount = do
input <- getContents
return . sum . map countNumbers . takeWhile (/= "") . lines $ input
All in all we get the following terse solution:
import Control.Monad (liftM)
import Data.Maybe (isJust)
import Text.Read (readMaybe)
readMaybeInt :: String -> Maybe Int
readMaybeInt = readMaybe
countNumbers :: String -> Int
countNumbers = length . filter isJust . map readMaybeInt . words
lineNumberCount :: IO Int
lineNumberCount =
getContents >>= return . sum . map countNumbers . takeWhile (/= "") . lines
Now there's only one function working in the IO monad, and all functions are basically applications of standard functions. Note that getContents will close the handle to the standard input. If you want to use you're better of using something like
input :: String -> IO [String]
input delim = do
ln <- getLine
if ln == delim then return []
else input delim >>= return . (ln:)
which will extract lines until a line matching delim has been found. Note that you need to change lineNumberCount in this case:
lineNumberCount :: IO Int
lineNumberCount =
input "" >>= return . sum . map countNumbers

Resources