Elegant haskell case/error handling in sequential monads - haskell

Because I oversimplified in my other question before, I would like to give a more clear example here.
How can I handle situations where I have to check for certian conditions in a sequential way without nesting multiple cases? With "sequential way" I mean getting a value (e.g. from stdin), checking this value for a certain condition and depending on the outcome getting another value and so on.
Example:
sequen :: IO String
sequen = do
a <- getLine
case a of
"hi" -> do
putStrLn "hello!"
b <- getLine
case b of
"how are you?" -> do
putStrLn "fine, thanks"
return "nice conversation"
_ -> return "error 2"
_ -> return "error 1"
I know that there are better ways to write such a chat bot, it should just demonstrate the sequential nature of the problem. As you can see, with every nested case, the code also gets indented deeper.
Is there a way to better structure such code? I'm thinking of handling the "errors" on one place and describing the "success-path" without the error handling distributed all over it.

Of course. This is precisely what EitherT was made for. You can get it from Control.Monad.Trans.Either in the eitherT package.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Either
main = do
e <- runEitherT $ do
a <- lift getLine
case a of
"hi" -> lift $ putStrLn "hello!"
_ -> left 1
b <- lift getLine
case b of
"how are you?" -> lift $ putStrLn "fine, thanks!"
_ -> left 2
return "nice conversation"
case e of
Left n -> putStrLn $ "Error - Code: " ++ show n
Right str -> putStrLn $ "Success - String: " ++ str
EitherT aborts the current code block whenever it encounters a left statement, and people typically use this to indicate error conditions.
The inner block's type is EitherT Int IO String. When you runEitherT it, you get IO (Either Int String). The Left type corresponds to the case where it failed with a left and the Right value means it successfully reached the end of the block.

I wrote a series of posts a while back going over my own learnings of the Either & EitherT types. You can read it here: http://watchchrislearn.com/blog/2013/12/01/working-entirely-in-eithert/
I use the errors package to get a bunch of nice helpers around using EitherT (left and right functions for instance to return lifted versions of Left and Right).
By extracting your potential failure conditions into their own helpers, you can make the mainline of your code read totally sequentially, with no case statements checking results.
From that post, you can see how the runEitherT section is a sequential chunk of work, it just happens to have the failure mechanics of EitherT. Obviously this code is fairly contrived to show how MaybeT plays inside of EitherT as well. In real code it'd just be the story you were wanting to tell, with a single Left/Right at the end.
import Control.Error
import Control.Monad.Trans
-- A type for my example functions to pass or fail on.
data Flag = Pass | Error
main :: IO ()
main = do
putStrLn "Starting to do work:"
result <- runEitherT $ do
lift $ putStrLn "Give me the first input please:"
initialText <- lift getLine
x <- eitherFailure Error initialText
lift $ putStrLn "Give me the second input please:"
secondText <- lift getLine
y <- eitherFailure Pass (secondText ++ x)
noteT ("Failed the Maybe: " ++ y) $ maybeFailure Pass y
case result of
Left val -> putStrLn $ "Work Result: Failed\n " ++ val
Right val -> putStrLn $ "Work Result: Passed\n " ++ val
putStrLn "Ok, finished. Have a nice day"
eitherFailure :: Monad m => Flag -> String -> EitherT String m String
eitherFailure Pass val = right $ "-> Passed " ++ val
eitherFailure Error val = left $ "-> Failed " ++ val
maybeFailure :: Monad m => Flag -> String -> MaybeT m String
maybeFailure Pass val = just $ "-> Passed maybe " ++ val
maybeFailure Error _ = nothing

Since you are necessarily in the IO monad, you are better off using the IO monad's error handling capabilities instead of stacking an error monad on top of IO. It avoids all of the heavy lifting:
import Control.Monad ( unless )
import Control.Exception ( catch )
import Prelude hiding ( catch )
import System.IO.Error ( ioeGetErrorString )
main' = do
a <- getLine
unless (a == "hi") $ fail "error 1"
putStrLn "hello!"
b <- getLine
unless (b == "how are you?") $ fail "error 2"
putStrLn "fine, thanks"
return "nice conversation"
main = catch main' $ return . ioeGetErrorString
In this case, your errors are simply Strings, which are thrown by IO's fail, as a userError. If you want to throw some other type, you will need to use throwIO instead of fail.

At some point the EitherT package was deprecated (though transformers-either offers a similar API). Fortunately there's an alternative to EitherT that doesn't even require installing a separate package.
The standard Haskell installation comes with the Control.Monad.Trans.Except module (from the transformers package, which is bundled with GHC), which behaves almost identically to EitherT. The resulting code is almost identical to the code in Gabriella Gonzalez's answer, but using runExceptT instead of runEitherT and throwE instead of left.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
main = do
e <- runExceptT $ do
a <- lift getLine
case a of
"hi" -> lift $ putStrLn "hello!"
_ -> throwE 1
b <- lift getLine
case b of
"how are you?" -> lift $ putStrLn "fine, thanks!"
_ -> throwE 2
return "nice conversation"
case e of
Left n -> putStrLn $ "Error - Code: " ++ show n
Right str -> putStrLn $ "Success - String: " ++ str
(Note that the aforementioned transformers-either package is in fact a wrapper for ExceptT designed for providing compatibility with code that still uses EitherT.)

Warning: fellow Haskell newbie answering.
You can avoid this sort of staircasing with the Maybe monad. Good example at the start of this chapter
However, you'd want something similar with a monadic Either (presumably there is one) since you're returning error codes.
The basic idea being that once you've got a "Left 1" error you'll short-circuit any future steps (because of lazy evaluation).

Related

Haskell: Handling resulting Either from computations

I have revisited Haskell lateley and constructed a toy programming language parser/interpreter. Using Parsec for lexing and parsing and a separate interpreter. I'm running in to some issues with feeding the result from the parser to my interpreter and handle the potential error from both the interpreter and parser. I end up with something like this:
main = do
fname <- getArgs
input <- readFile (head fname)
case lparse (head fname) input of
Left msg -> putStrLn $ show msg
Right p -> case intrp p of
Left msg -> putStrLn $ show msg
Right r -> putStrLn $ show r
This dosn't look pretty at all. My problem is that lparse returns Either ParseError [(String, Stmt)] and itrp returns the type Either ItrpError Stmt so I'm having a real hard time feeding the Right result from the parser to the interpreter and at the same time bail and print the possible ParseError or IntrpError.
The closest to what i want is something like this
main = do
fname <- getArgs
input <- readFile (head fname)
let prog = lparse (head fname) input
(putStrLn . show) (intrp <$> prog)
But this will not surprisingly yield a nested Either and not print pretty either.
So are there any nice Haskell ideomatic way of doing this threading results from one computation to another and handling errors (Lefts) in a nice way without nesting cases?
Edit
adding types of lparse and itrp
lparse :: Text.Parsec.Pos.SourceName -> String -> Either Text.Parsec.Error.ParseError [([Char], Stmt)]
intrp :: [([Char], Stmt)] -> Either IntrpError Stmt
While not perfect, I'd create a helper function for embedding any Showable error from Either into MonadError:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Except
strErr :: (MonadError String m, Show e) => Either e a -> m a
strErr = either (throwError . show) return
Then if you have a computation that can fail with errors, like
someFn :: ExceptT String IO ()
someFn = strErr (Left 42)
you can run it (printing errors to stdout) as
main :: IO ()
main = runExceptT someFn >>= either putStrLn return
In your case it'd be something like
main = either putStrLn return <=< runExceptT $ do
fname <- liftIO getArgs
input <- liftIO $ readFile (head fname)
prog <- strErr $ lparse (head fname) input
r <- strErr $ interp prog
print r
Well, if you want to chain successful computations, you can always use >>= to do that. For instance in your case:
lparse (head fname) input >>= intrp
And if you want to print out either your error message you can use the either class that takes two handler functions, one for the case when you have Left a (error in your case) and another for Right b (in your case a successful thing). An example:
either (putStrLn . show) (putStrLn . show) (lparse (head fname) input >>= intrp)
And if anything fails in your chain (any step of your monadic chain becomes Left a) it stops and can for instance print out the error message in the above case.

Handling exceptions (ExceptT) in chain of actions

I am trying to use an exception to skip parts of the code here. Instead of getting caught by catcheE and resuming normal behavior all following actions in the mapM_ chain get skipped.
I looked at this question and it appears that catchE ~ main and checkMaybe ~ intercept.
I also checked the implementation of mapM_to be sure it does what i want it to, but i don't understand how the Left value can escape dlAsset to affect the behavior of mapM_.
I refactored this from a version where i simply used an empty string as an exception marker for the failed lookup. In that version checkMaybe just returned a Right value immediately and it worked (matching on "" to 'catch')
import Data.HashMap.Strict as HM hiding (map)
import qualified Data.ByteString.Lazy as BS
import qualified Data.ByteString.Char8 as BSC8
import qualified JSONParser as P -- my module
retrieveAssets :: (Text -> Text) -> ExceptT Text IO ()
retrieveAssets withName = withManager $ (lift ((HM.keys . P.assets)
<$> P.raw) ) >>= mapM_ f
where
f = \x -> dlAsset x "0.1246" (withName x)
dlAsset :: Text -> Text -> Text -> ReaderT Manager (ExceptT Text IO) ()
dlAsset name size dest = do
req <- lift $ (P.assetLookup name size <$> P.raw) >>= checkMaybe
name >>= parseUrl . unpack -- lookup of a url
res <- httpLbs req
lift $ (liftIO $ BS.writeFile (unpack dest) $ responseBody res)
`catchE` (\_ -> return ()) -- always a Right value?
where
checkMaybe name a = case a of
Nothing -> ExceptT $ fmap Left $ do
BSC8.appendFile "./resources/images/missingFiles.txt" $
BSC8.pack $ (unpack name) ++ "\n"
putStrLn $ "lookup of " ++ (unpack name) ++ " failed"
return name
Just x -> lift $ pure x
(had to reformat to become somewhat readable here)
edit: i'd like to understand what actually happens here, that would probably help me more than knowing which part of the code is wrong.
The problem is that your call to catchE only covered the very last line of dlAsset. It needs to be moved to the left of the do-notation indentation level to cover all of the do notation.

How to "break" IO action in haskell

I want to have the "return" (in imperative language) function in haskell.
E.g.
main = do
let a = 10
print a
-- return this function
print $ a + 1
How can I achieve this?
You can emulate this to some extent using Exceptions,
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Exception
import Data.Typeable
data MyException = MyException deriving (Show, Typeable)
instance Exception MyException
main = handle (\ MyException -> return ()) $ do
let a = 10 :: Int
print a
throwIO MyException
print $ a + 1 -- never gets executed
You can also do it with the ContT or ErrorT monad transformers, although they can a bit unwieldly.
First, let me start by warning that trying to translate imperative constructs into Haskell will likely lead to code which is not idiomatic, hard to write, and hard to read. Just because you can simulate some constructs by using a few monad transformers, it does not mean that this should actually be done.
That being said, here's an example of early return using Control.Monad.Cont.ContT. The code below simulates an imperative return inside a few for loops.
As Rufflewind warns, this can get unwieldy. The type of callCC alone (not shown below) can be quite puzzling.
import Control.Monad.Cont
search :: Int -> IO (Maybe (Int,Int))
search x = runContT (callCC go) return
where go earlyReturn = do
forM_ [10..50] $ \i -> do
lift $ putStrLn $ "Trying i=" ++ show i
forM_ [10..50] $ \j -> do
lift $ putStrLn $ "Trying j=" ++ show j
when (i * j == x) $ do
lift $ putStrLn $ "Found " ++ show (i,j)
earlyReturn $ Just (i,j)
return Nothing

Haskell Best Practise: Early termination in Haskeline

I am using the Haskeline package and I want to get three strings in a row from the command line before I do anything and I have come up with what seems to be a neat solution to me. But I am sure that there might be a better way to do it. I am looking for best practices while using the Haskeline package. Please evaluate the merits of the following example code:
import System.Console.Haskeline
import Control.Monad.Trans
import Control.Monad.Maybe
import Data.Maybe
import Control.Monad
main :: IO ()
main = runInputT defaultSettings (runMaybeT getStrings) >>= print
getStrings :: MaybeT (InputT IO) (String, String, String)
getStrings = do
mone <- lift $ getInputLine "food> "
notNothing mone
mtwo <- lift $ getInputLine "drink> "
notNothing mtwo
mthree <- lift $ getInputLine "dessert> "
notNothing mthree
return (fromJust mone, fromJust mtwo, fromJust mthree)
where
notNothing a = guard (a /= Nothing)
As you can see it accomplishes the task of early termination but it looks a bit yucky still. I'm thinking of trying to convert the notNothing's and the getInputLine's into a single line like:
mone <- notNothing =<< lift $ getInputLine "food> " -- does not type check
Which I think does not look that bad. I think that is pretty clear and concise (though it does not type check so I will have to write a version that does).
However, this is the best I have come up with and my question finally is: How would you go about improving this code to be neater and more readily readable? Am I even on the right track?
Edit: If your guard is something other than 'a /= Nothing' then a nice helper function that I just discovered is:
myGuard s = guard (someConditionFunc s) >> s
Because then you can write (as luqui suggested):
mone <- myGuard =<< (lift $ getInputLine prompt)
Which is pretty cool. But if you are matching against only Nothing then TomMD's answer is better.
Why not just leverage the fact that fail _ = Nothing for the Maybe monad?
mthree <- lift $ getInputLine "dessert> "
notNothing mthree
becomes
Just mthree <- lift $ getInputLine "dessert> "
How about a helper function?
inputLine :: String -> MaybeT (InputT IO) String
inputLine prompt = do
m <- lift $ getInputLine prompt
case m of
Just x -> return x
Nothing -> mzero
This can be shortened considerably using various tricks, but I wanted to be clear. Now you can just forget that getInputLine can fail, MaybeT takes care of that for you.

Convert a "do" notation with more than two actions to use the bind function

I know that the following "do" notation's "bind" function is equivalent to getLine >>= \line -> putStrLn
do line <- getLine
putStrLn line
But how is the following notation equivalent to bind function?
do line1 <- getLine
putStrLn "enter second line"
line2 <- getLine
return (line1,line2)
I take it you are trying to see how to bind the result of "putStrLn". The answer is in the type of putStrLn:
putStrLn :: String -> IO ()
Remember that "()" is the unit type, which has a single value (also written "()"). So you can bind this in exactly the same way. But since you don't use it you bind it to a "don't care" value:
getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)
As it happens, there is an operator already defined for ignoring the return value, ">>". So you could just rewrite this as
getLine >>= \line1 ->
putStrLn "enter second line" >>
getline >>= \line2 ->
return (line1, line2)
I'm not sure if you are also trying to understand how bind operators are daisy-chained. To see this, let me put the implicit brackets and extra indentation in the example above:
getLine >>= (\line1 ->
putStrLn "enter second line" >> (
getline >>= (\line2 ->
return (line1, line2))))
Each bind operator links the value to the left with a function to the right. That function consists of all the rest of the lines in the "do" clause. So the variable being bound through the lambda ("line1" in the first line) is in scope for the whole of the rest of the clause.
For this specific example you can actually avoid both do and >>= by using combinators from Control.Applicative:
module Main where
import Control.Applicative ((<$>), (<*>), (<*))
getInput :: IO (String, String)
getInput = (,) <$> getLine <* putStrLn "enter second line" <*> getLine
main = print =<< getInput
Which works as expected:
travis#sidmouth% ./Main
hello
enter second line
world
("hello","world")
It looks a little weird at first, but in my opinion the applicative style feels very natural once you're used to it.
I would strongly suggest you to read the chapter Desugaring of Do-blocks in the book Real-World haskell. It tells you, that you all are wrong. For a programmer, it's the natural way to use a lambda, but the do-block is implemented using functions which - if a pattern maching failuire occurs - will call the fail implementation of the according monad.
For instance, your case is like:
let f x =
putStrLn "enter second line" >>
let g y = return (x,y)
g _ = fail "Pattern mismatched"
in getLine >>= g
f _ = fail "Pattern mismatched"
in getLine >>= f
In a case like this, this may be completely irrelevant. But consider some expression that involves pattern-matching. Also, you can use this effect for some special stuff, eg, you can do something like this:
oddFunction :: Integral a => [a] -> [a]
oddFunctiond list = do
(True,y) <- zip (map odd list) list
return y
What will this function do? You can read this statement as a rule for working with the elements of the list. The first statement binds an element of the list to the var y, but only if y is odd. If y is even, a pattern matching failure occurs and fail will be called. In the monad instance for Lists, fail is simply []. Thus, the function strips all even elements from the list.
(I know, oddFunction = filter odd would do this better, but this is just an example)
getLine >>= \line1 ->
putStrLn "enter second line" >>
getLine >>= \line2 ->
return (line1, line2)
Generally foo <- bar becomes bar >>= \foo -> and baz becomes baz >> (unless it's the last line of the do-block, in which case it just stays baz).

Resources