How do I catch read exceptions in Haskell? - haskell

In the following Haskell code:
data Cmd =
CmdExit |
CmdOther
deriving (Read, Show)
guiString2Cmd s =
(return (read s :: Cmd)) `catch` \(e :: SomeException) -> return CmdExit
If I do:
guiString2Cmd "CmdOther"
it all works fine. However if I do:
guiString2Cmd "some wrong string"
the code crashes instead of evaluating to CmdExit.
How can I make the code handle the exception instead of crashing?

Use the reads function, which is total, and wrap the failure case as a Maybe, like so:
maybeRead :: Read a => String -> Maybe a
maybeRead s = case reads s of
[(x, "")] -> Just x
_ -> Nothing
maybeRead is quite a versatile way to do safe parsing.

A solution is to simply use reads instead.

There exists an idiom of reading inside a monad:
readM :: (Monad m, Read a) => String -> m a
readM s | [x] <- [x | (x, "") <- reads s] = return x
-- or #[x] <- [x | (x, _) <- reads s] = return x#
-- to allow the garbage at the end of parsed string
| otherwise = fail $ "Failed to parse: \"" ++ s ++ "\""
it's unsafe for the IO monad:
> readM "CmdOther" :: IO Cmd
CmdOther
> readM "Cmd?Other" :: IO Cmd
*** Exception: user error (Failed to parse: "Cmd?Other")
because fail throws an IOError exception in the case of IO, which, however, can be handled:
*Main> (readM "Cmd?Other" :: IO Cmd) `catch` const (return CmdOther)
CmdOther
And safe in the case of Maybe monad:
> readM "CmdOther" :: Maybe Cmd
Just CmdOther
> readM "Cmd?Other" :: Maybe Cmd
Nothing
because fail is const Nothing in this case.
Anyway, if you want a total function guiString2Cmd with a signature String -> Cmd you can write it just like readM:
guiString2Cmd :: String -> Cmd
guiString2Cmd s | [x] <- [x | (x, "") <- reads s] = x
| otherwise = CmdExit
and then:
> guiString2Cmd "CmdOther"
CmdOther
> guiString2Cmd "Cmd?Other"
CmdExit
Slightly more generic approach.
For * kinds:
class Failable0 t where
fail0 :: t
readG0 :: (Failable0 t, Read t) => String -> t
readG0 s | [x] <- [x | (x, "") <- reads s] = x
| otherwise = fail0
then:
instance Failable0 Cmd where
fail0 = CmdExit
For * -> * kinds:
class Failable f where
fail :: String -> f a
class Functor f => Pointed f where
pure :: a -> f a
readG :: (Failable f, Pointed f, Read a) => String -> f a
readG s | [x] <- [x | (x, "") <- reads s] = pure x
| otherwise = fail $ "Failed to parse: \"" ++ s ++ "\""

I would personally recommend using readMay from the safe package:
readMay :: Read a => String -> Maybe a
Then you can either pattern-match on the 'Maybe a' result, use 'maybe', or even use the 'Maybe' monad to handle the result.

Related

Function Loop in string too long

i have these functions:
item :: Parser Char
item = Parser i
where i [] = []
i (x:xs) = [(x,xs)]
many :: Eq a=> Parser a -> Parser [a]
many p = many1 p +++ return []
many1 :: Eq a=> Parser a -> Parser [a]
many1 p = do v <- p
vs <- many p
returns (v:vs)
Im getting strange results applying differents strings. If i execute:
parse (many item) "x:=0"
i get
[('x',0)]
while if i use another string longer like "if x=0 then x:=0 else x:=1" it looks like go in loop. Doing some attempts it seems that if the string is longer more than 19 chars the function doesnt end. It's strange because on other string long less 19 chars it works good. What it could be?
Other definitions:
newtype Parser a = Parser { parse :: String -> [(a, String)] }
instance Monad Parser where
return t = Parser $ \s -> [(t, s)]
m >>= k = Parser $ \s -> [(x, y) | (u, v) <- parse m s, (x, y) <- parse (k u) v]
(+++) :: Eq a => Parser a -> Parser a -> Parser a
p +++ q = Parser $ \s -> if((parse p s)==[]) then parse q s else parse p s
Your code works fine, it's just that you've written your parser to have infinite backtracking and therefore O(2^n) runtime. Every character you add doubles the time it takes to complete:
$ time hugs foo.hs <<< 'parse (many item) "if x=0 then x:=0 els"'
[...]
Main> [("if x=0 then x:=0 els","")]
Main> [Leaving Hugs]
real 0m11.076s
user 0m10.578s
sys 0m0.016s
vs
$ time hugs foo.hs <<< 'parse (many item) "if x=0 then x:=0 else"'
[...]
Main> [("if x=0 then x:=0 else","")]
Main> [Leaving Hugs]
real 0m22.346s
user 0m22.048s
sys 0m0.036s
Your implementation of (+++) doesn’t do what you think it does. In particular, it will only return successful parsed from one of its arguments, rather than from both. Here is how to do what you want:
(+++) :: Parser a -> Parser a -> Parser a
p +++ q = Parser $ \s -> parse p s ++ parse q s
Although this doesn’t remove duplicates so be warned that you can end up with an explosion of parses by doing eg many (many item).

What is the difference between `readMay` and `readMaybe`?

The two functions readMay and readMaybe have the same signature Read a => String -> Maybe a.
Is there any difference between them? If so, what are they? Which of the two function should be preferred?
There is no difference. Here's how readMay's defined:
-- | This function provides a more precise error message than 'readEither' from 'base'.
readEitherSafe :: Read a => String -> Either String a
readEitherSafe s = case [x | (x,t) <- reads s, ("","") <- lex t] of
[x] -> Right x
[] -> Left $ "no parse on " ++ prefix
_ -> Left $ "ambiguous parse on " ++ prefix
where
maxLength = 15
prefix = '\"' : a ++ if length s <= maxLength then b ++ "\"" else "...\""
where (a,b) = splitAt (maxLength - 3) s
readMay :: Read a => String -> Maybe a
readMay = eitherToMaybe . readEitherSafe
And here is readMaybe:
-- | Parse a string using the 'Read' instance.
-- Succeeds if there is exactly one valid result.
-- A 'Left' value indicates a parse error.
--
-- #since 4.6.0.0
readEither :: Read a => String -> Either String a
readEither s =
case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
[x] -> Right x
[] -> Left "Prelude.read: no parse"
_ -> Left "Prelude.read: ambiguous parse"
where
read' =
do x <- readPrec
lift P.skipSpaces
return x
-- | Parse a string using the 'Read' instance.
-- Succeeds if there is exactly one valid result.
--
-- #since 4.6.0.0
readMaybe :: Read a => String -> Maybe a
readMaybe s = case readEither s of
Left _ -> Nothing
Right a -> Just a
They differ in the intermediate error message (readEitherSafe shows the input), but the result will be same.
readMay from Safe predates readMaybe from Text.Read. Unless you're on a base version less than 4.6.0.0, use readMaybe from Text.Read as it does not need another package.

IO action nested in other monads not executing

I have a
foobar :: IO (ParseResult [(String,String)])
ParseResult is a monad defined here: https://hackage.haskell.org/package/haskell-src-exts-1.13.5/docs/Language-Haskell-Exts-Parser.html#t:ParseResult
I want to take those strings and write them to a LaTeXT m () defined in https://hackage.haskell.org/package/HaTeX-3.17.1.0/docs/Text-LaTeX-Base-Writer.html
Running this function results in no file being created.
writeReport2 :: [Char] -> IO (ParseResult (IO ()))
writeReport2 name = do x <- foobar
return $ do y <- x
return $ do z <- (execLaTeXT.docAndGraph) y
renderFile fileName z
where
fileName = name ++ ".tex"
However the code:
writeReport :: t -> LaTeXT IO a -> IO ()
writeReport name report = createLatex >>= renderFile fileName
where
createLatex = execLaTeXT report
fileName = "AAAAA" ++ ".tex"
testFoo = [(" | HaskellExample Example File\n | Two examples are given below:\n\n >>> fib 10\n 55\n\n >>> putStrLn \"foo\\nbar\"\n foo\n bar ","fib :: Int -> Int"),("\n | This is a thing: ","fib = undefined"),("\n | This is a thing:\n","fibar :: String -> Float")]
itWorks = writeReport "AAAA.txt" $ docAndGraph testFoo
Will create a new file.
Both sets of code type check.
I could get writeReport2 working without modification.
I think what might have been your problem is the nested IO action in the return value of writeResport2!
In order to flatten the nested IO actions, I had to use the function join :: Monad m => m (m a) -> m a from Control.Monad:
main :: IO ()
main = join $ fromParseResult <$> writeReport2 "test"
Here is my complete code:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Language.Haskell.Exts.Parser
import Text.LaTeX.Base.Writer
import Text.LaTeX
import Data.String
import Control.Monad
foobar :: IO (ParseResult [(String, String)])
foobar = return (ParseOk testFoo)
testFoo = [ ( " | HaskellExample Example File\n | Two examples are given below:\n\n >>> fib 10\n 55\n\n >>> putStrLn \"foo\\nbar\"\n foo\n bar "
, "fib :: Int -> Int"
)
, ("\n | This is a thing: ", "fib = undefined")
, ("\n | This is a thing:\n", "fibar :: String -> Float")
]
docAndGraph :: Monad m => [(String, String)] -> LaTeXT m ()
docAndGraph x = do
documentclass [] article
document $
raw (fromString (show x))
writeReport2 :: [Char] -> IO (ParseResult (IO ()))
writeReport2 name = do
x <- foobar
return $ do
y <- x
return $ do
z <- (execLaTeXT . docAndGraph) y
renderFile fileName z
where
fileName = name ++ ".tex"
main :: IO ()
main = join $ fromParseResult <$> writeReport2 "test"
Loading into GHCi:
$ stack ghci
io-action-nested-in-other-monads-not-executing-0.1.0.0: initial-build-steps (exe)
Configuring GHCi with the following packages: io-action-nested-in-other-monads-not-executing
Using main module: 1. Package `io-action-nested-in-other-monads-not-executing' component exe:io-action-nested-in-other-monads-not-executing with main-is file: /home/sven/dev/stackoverflow-questions/io-action-nested-in-other-monads-not-executing/src/Main.hs
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sven/.ghc/ghci.conf
[1 of 1] Compiling Main ( /home/sven/dev/stackoverflow-questions/io-action-nested-in-other-monads-not-executing/src/Main.hs, interpreted )
Ok, modules loaded: Main.
Loaded GHCi configuration from /tmp/ghci22616/ghci-script
And running it:
λ main
Creates this file:
$ cat test.tex
\documentclass{article}\begin{document}[(" | HaskellExample Example File\n | Two examples are given below:\n\n >>> fib 10\n 55\n\n >>> putStrLn \"foo\\nbar\"\n foo\n bar ","fib :: Int -> Int"),("\n | This is a thing: ","fib = undefined"),("\n | This is a thing:\n","fibar :: String -> Float")]\end{document}%
I know it is not the scope of the question, but you could circumvent the nested IO if you want, by doinf this, for example:
writeReport3 :: [Char] -> IO ()
writeReport3 name = do
let fileName = name ++ ".tex"
x <- foobar
case x of
ParseOk y -> do
z <- execLaTeXT (docAndGraph y)
renderFile fileName z
ParseFailed _ _ ->
return ()
main :: IO ()
main = writeReport3 "test"

Haskell: Exception <<loop>> on recursive data entry

So I'm trying to make a little program that can take in data captured during an experiment, and for the most part I think I've figured out how to recursively take in data until the user signals there is no more, however upon termination of data taking haskell throws Exception: <<loop>> and I can't really figure out why. Here's the code:
readData :: (Num a, Read a) => [Point a] -> IO [Point a]
readData l = do putStr "Enter Point (x,y,<e>) or (d)one: "
entered <- getLine
if (entered == "d" || entered == "done")
then return l
else do let l = addPoint l entered
nl <- readData l
return nl
addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a]
addPoint l s = l ++ [Point (dataList !! 0) (dataList !! 1) (dataList !! 2)]
where dataList = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a]
checkInputData :: [String] -> [String]
checkInputData xs
| length xs < 2 = ["0","0","0"]
| length xs < 3 = (xs ++ ["0"])
| length xs == 3 = xs
| length xs > 3 = ["0","0","0"]
As far as I can tell, the exception is indication that there is an infinite loop somewhere, but I can't figure out why this is occurring. As far as I can tell when "done" is entered the current level should simply return l, the list it's given, which should then cascade up the previous iterations of the function.
Thanks for any help. (And yes, checkInputData will have proper error handling once I figure out how to do that.)
<<loop>> basically means GHC has detected an infinite loop caused by a value which depends immediately on itself (cf. this question, or this one for further technical details if you are curious). In this case, that is triggered by:
else do let l = addPoint l entered
This definition, which shadows the l you passed as an argument, defines l in terms of itself. You meant to write something like...
else do let l' = addPoint l entered
... which defines a new value, l', in terms of the original l.
As Carl points out, turning on -Wall (e.g. by passing it to GHC at the command line, or with :set -Wall in GHCi) would make GHC warn you about the shadowing:
<interactive>:171:33: warning: [-Wname-shadowing]
This binding for ‘l’ shadows the existing binding
bound at <interactive>:167:10
Also, as hightlighted by dfeuer, the whole do-block in the else branch can be replaced by:
readData (addPoint l entered)
As an unrelated suggestion, in this case it is a good idea to replace your uses of length and (!!) with pattern matching. For instance, checkInputData can be written as:
checkInputData :: [String] -> [String]
checkInputData xs = case xs of
[_,_] -> xs ++ ["0"]
[_,_,_] -> xs
_ -> ["0","0","0"]
addPoint, in its turn, might become:
addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a]
addPoint l s = l ++ [Point x y z]
where [x,y,z] = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a]
That becomes even neater if you change checkInputData so that it returns a (String, String, String) triple, which would better express the invariant that you are reading exactly three values.

Formatting long pattern matching

I want format this function:
getEnv :: [Func] -> ([Char] -> RetType)
getEnv [] = (\_ -> undefined)
getEnv ((Func (RetTypeType t) (Ident fname) _ _):fs) = (\x -> if x == fname then t else getEnv fs)
The problem is caused by a long pattern matching, and for now I don't want to change the names of constructors. Also the right part of the function at the third line is not easy to formatting for me.
Although is not matter of life or death, I'm curios how you format this code. Thanks.
Basically, you have two possibilities:
Something like this:
getEnv ((Func
(RetTypeType t)
(Ident fname) _ _)
:fs)
= (\x -> if x == fname then t else getEnv fs)
or you can use pattern guards:
getEnv (h:fs)
| Func a b _ _ <- h,
Rectype t <- a,
Ident fname <- b
= (\x -> if x == fname then t else getEnv fs)
You could furthermore avoid the lambda:
getEnv (h:fs) x
| Func a b _ _ <- h,
Rectype t <- a,
Ident fname <- b
= if x == fname then t else getEnv fs
The downside with "open" pattern guards may be that the compiler cannot decide anymore whether your patterns are exhaustive.
As #leftaroundabout points out, we can put it even more clearly thus:
getEnv (h:fs) x
| Func a b _ _ <- h,
Rectype t <- a,
Ident fname <- b,
x == fname = t
| otherwise = getEnv fs
This will also let the compiler know that all possible forms of the head of the list are covered, so this I'd term the most preferred way to do it.
I would usually simply do
getEnv :: [Func] -> ([Char] -> RetType)
getEnv [] = (\_ -> undefined)
getEnv ((Func (RetTypeType t) (Ident fname) _ _):fs)
= \x -> if x == fname then t else getEnv fs
However I'd be inclined if I was doing a lot of that to use record syntax
data Func = Func {returnTypeType :: RetTypeType,
identifier :: Ident,
.... }
data RetTypeType = RetTypeType {unRetTypeType :: RetType}
data Ident = Ident {unIdent:: String}
so I could write
getEnv :: [Func] -> ([Char] -> RetType)
getEnv [] = (\_ -> undefined)
getEnv (f:fs) = \x -> if x == ident f
then unRetTypeType.returnTypeType $ f
else getEnv fs
First of all, I try to keep patterns simple. Usually it's just one constructor with variables or underscores as it's arguments. Exception: built-in constructors like (:) or (,) don't count. So, if you have that kind of pattern-matching, I think you are doing something wrong.
Secondly, I would just split the line at '=' and be happy.

Resources