Monadic function fails as Nothing in Maybe context but as Exception in Either context.

I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left. Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph. type MyGraph = Gr String String tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph Here's the code: import Data.Graph.Inductive -- FGL, the Functional Graph Library gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g' replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph [1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/... -- Jeffrey Benjamin Brown

Hi, Jeffrey in short: `fail` of `Either e` throws an exception (i.e. is not overriden, default implementation is `fail s = error s`) [1, 2] For `Maybe`, fail is defined as `fail _ = Nothing`; which is good default. [3] You probably want to use for example `throwError from `mtl` package [4]: gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else throwError "Node not in Graph" -- False otherwise [1] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... [2] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... [3] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... [4] http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#... http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#... - Oleg
On 01 Dec 2015, at 00:25, Jeffrey Brown
wrote: I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph.
type MyGraph = Gr String String
tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph
maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing
eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph
Here's the code:
import Data.Graph.Inductive -- FGL, the Functional Graph Library
gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise
replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g'
replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph
[1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/... https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/...
-- Jeffrey Benjamin Brown _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

On 01 Dec 2015, at 00:34, Oleg Grenrus
wrote: Hi, Jeffrey
in short: `fail` of `Either e` throws an exception (i.e. is not overriden, default implementation is `fail s = error s`) [1, 2]
For `Maybe`, fail is defined as `fail _ = Nothing`; which is good default. [3]
You probably want to use for example `throwError from `mtl` package [4]:
I haven’t still tested it, but less wrong context is `MonadError String m`: gelemM :: (MonadError String m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else throwError "Node not in Graph" -- False otherwise
[1] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... [2] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... [3] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... [4] http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#... http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#...
- Oleg
On 01 Dec 2015, at 00:25, Jeffrey Brown
mailto:jeffbrown.the@gmail.com> wrote: I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph.
type MyGraph = Gr String String
tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph
maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing
eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph
Here's the code:
import Data.Graph.Inductive -- FGL, the Functional Graph Library
gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise
replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g'
replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph
[1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/... https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/...
-- Jeffrey Benjamin Brown _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org mailto:Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

Oleg's suggestion works! I just had to add these two lines in order to use
it:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Except -- mtl library
Thanks, everybody!
On Mon, Nov 30, 2015 at 2:38 PM, Oleg Grenrus
On 01 Dec 2015, at 00:34, Oleg Grenrus
wrote: Hi, Jeffrey
in short: `fail` of `Either e` throws an exception (i.e. is not overriden, default implementation is `fail s = error s`) [1, 2]
For `Maybe`, fail is defined as `fail _ = Nothing`; which is good default. [3]
You probably want to use for example `throwError from `mtl` package [4]:
I haven’t still tested it, but less wrong context is `MonadError String m`:
gelemM :: (MonadError String m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else throwError "Node not in Graph" -- False otherwise
[1] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... [2] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... [3] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... [4] http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#...
- Oleg
On 01 Dec 2015, at 00:25, Jeffrey Brown
wrote: I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph.
type MyGraph = Gr String String
tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph
maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing
eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph
Here's the code:
import Data.Graph.Inductive -- FGL, the Functional Graph Library
gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise
replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g'
replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph
[1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/...
-- Jeffrey Benjamin Brown _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Jeffrey Benjamin Brown

I spoke too soon; I'm seeing the same problem with MonadError.
Prelude> :set -XFlexibleContexts
Prelude> import Control.Monad.Except
Prelude Control.Monad.Except> let f = (fail "be Left!" :: (MonadError
String m) => m ())
Loading package transformers-0.4.2.0 ... linking ... done.
Loading package mtl-2.2.1 ... linking ... done.
Prelude Control.Monad.Except> f :: Either String ()
*** Exception: be Left!
Prelude Control.Monad.Except>
On Mon, Nov 30, 2015 at 6:18 PM, Jeffrey Brown
Oleg's suggestion works! I just had to add these two lines in order to use it:
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Except -- mtl library
Thanks, everybody!
On Mon, Nov 30, 2015 at 2:38 PM, Oleg Grenrus
wrote: On 01 Dec 2015, at 00:34, Oleg Grenrus
wrote: Hi, Jeffrey
in short: `fail` of `Either e` throws an exception (i.e. is not overriden, default implementation is `fail s = error s`) [1, 2]
For `Maybe`, fail is defined as `fail _ = Nothing`; which is good default. [3]
You probably want to use for example `throwError from `mtl` package [4]:
I haven’t still tested it, but less wrong context is `MonadError String m`:
gelemM :: (MonadError String m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else throwError "Node not in Graph" -- False otherwise
[1] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... [2] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... [3] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... [4] http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#...
- Oleg
On 01 Dec 2015, at 00:25, Jeffrey Brown
wrote: I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph.
type MyGraph = Gr String String
tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph
maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing
eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph
Here's the code:
import Data.Graph.Inductive -- FGL, the Functional Graph Library
gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise
replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g'
replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph
[1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/...
-- Jeffrey Benjamin Brown _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Jeffrey Benjamin Brown
-- Jeffrey Benjamin Brown

Use `throwError`, not `fail`. :) Forget `fail`. Luckily we are taking it out of `Monad`. - Oleg
On 01 Dec 2015, at 20:44, Jeffrey Brown
wrote: I spoke too soon; I'm seeing the same problem with MonadError.
Prelude> :set -XFlexibleContexts Prelude> import Control.Monad.Except Prelude Control.Monad.Except> let f = (fail "be Left!" :: (MonadError String m) => m ()) Loading package transformers-0.4.2.0 ... linking ... done. Loading package mtl-2.2.1 ... linking ... done. Prelude Control.Monad.Except> f :: Either String () *** Exception: be Left! Prelude Control.Monad.Except>
On Mon, Nov 30, 2015 at 6:18 PM, Jeffrey Brown
mailto:jeffbrown.the@gmail.com> wrote: Oleg's suggestion works! I just had to add these two lines in order to use it: {-# LANGUAGE FlexibleContexts #-} import Control.Monad.Except -- mtl library
Thanks, everybody!
On Mon, Nov 30, 2015 at 2:38 PM, Oleg Grenrus
mailto:oleg.grenrus@iki.fi> wrote: On 01 Dec 2015, at 00:34, Oleg Grenrus
mailto:oleg.grenrus@iki.fi> wrote: Hi, Jeffrey
in short: `fail` of `Either e` throws an exception (i.e. is not overriden, default implementation is `fail s = error s`) [1, 2]
For `Maybe`, fail is defined as `fail _ = Nothing`; which is good default. [3]
You probably want to use for example `throwError from `mtl` package [4]:
I haven’t still tested it, but less wrong context is `MonadError String m`:
gelemM :: (MonadError String m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else throwError "Node not in Graph" -- False otherwise
[1] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... [2] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... [3] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... [4] http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#... http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#...
- Oleg
On 01 Dec 2015, at 00:25, Jeffrey Brown
mailto:jeffbrown.the@gmail.com> wrote: I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph.
type MyGraph = Gr String String
tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph
maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing
eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph
Here's the code:
import Data.Graph.Inductive -- FGL, the Functional Graph Library
gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise
replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g'
replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph
[1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/... https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/...
-- Jeffrey Benjamin Brown _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org mailto:Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org mailto:Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Jeffrey Benjamin Brown
-- Jeffrey Benjamin Brown

Right! That's what I was doing when I got it to work and then I forgot. I
will correct the habit. Sorry for the annoyance!
On Tue, Dec 1, 2015 at 10:46 AM, Oleg Grenrus
Use `throwError`, not `fail`. :)
Forget `fail`. Luckily we are taking it out of `Monad`.
- Oleg
On 01 Dec 2015, at 20:44, Jeffrey Brown
wrote: I spoke too soon; I'm seeing the same problem with MonadError.
Prelude> :set -XFlexibleContexts Prelude> import Control.Monad.Except Prelude Control.Monad.Except> let f = (fail "be Left!" :: (MonadError String m) => m ()) Loading package transformers-0.4.2.0 ... linking ... done. Loading package mtl-2.2.1 ... linking ... done. Prelude Control.Monad.Except> f :: Either String () *** Exception: be Left! Prelude Control.Monad.Except>
On Mon, Nov 30, 2015 at 6:18 PM, Jeffrey Brown
wrote: Oleg's suggestion works! I just had to add these two lines in order to use it:
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Except -- mtl library
Thanks, everybody!
On Mon, Nov 30, 2015 at 2:38 PM, Oleg Grenrus
wrote: On 01 Dec 2015, at 00:34, Oleg Grenrus
wrote: Hi, Jeffrey
in short: `fail` of `Either e` throws an exception (i.e. is not overriden, default implementation is `fail s = error s`) [1, 2]
For `Maybe`, fail is defined as `fail _ = Nothing`; which is good default. [3]
You probably want to use for example `throwError from `mtl` package [4]:
I haven’t still tested it, but less wrong context is `MonadError String m`:
gelemM :: (MonadError String m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else throwError "Node not in Graph" -- False otherwise
[1] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html#l... [2] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#Mona... [3] https://hackage.haskell.org/package/base-4.8.1.0/docs/src/GHC.Base.html#line... [4] http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#...
- Oleg
On 01 Dec 2015, at 00:25, Jeffrey Brown
wrote: I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
Here's a tiny demonstration. "tinyGraph" below has one Node, 0, with the label "dog". If I try to change the label at Node 0 to "cat", it works. If I try to change the label at Node 1 to "cat", it fails, because Node 1 is not in the graph.
type MyGraph = Gr String String
tinyGraph = mkGraph [(0, "dog")] [] :: MyGraph
maybeSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Maybe MyGraph -- == Just (mkGraph [(0,"cat")] []) maybeFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Maybe MyGraph -- == Nothing
eitherSucceed = replaceStringAtNodeM tinyGraph 0 "cat" :: Either String MyGraph -- == Right (mkGraph [(0,"cat")] []) eitherFail = replaceStringAtNodeM tinyGraph 1 "cat" :: Either String MyGraph -- *** Exception: Node not in Graph
Here's the code:
import Data.Graph.Inductive -- FGL, the Functional Graph Library
gelemM :: (Monad m) => MyGraph -> Node -> m () gelemM g n = if gelem n g -- FGL's gelem function returns then return () -- True if the node is in the graph else fail "Node not in Graph" -- False otherwise
replaceStringAtNode :: MyGraph -> Node -> String -> MyGraph replaceStringAtNode g n e = let (Just (a,b,c,d),g') = match n g in (a,b,e,d) & g'
replaceStringAtNodeM :: (Monad m) => MyGraph -> Node -> String -> m MyGraph replaceStringAtNodeM g n s = do gelemM g n return $ replaceStringAtNode g n s -- if evaluated, the pattern match in replaceStringAtNode must succeed, -- because gelemM catches the case where n is not in the graph
[1] https://github.com/JeffreyBenjaminBrown/digraphs-with-text/blob/master/test/...
-- Jeffrey Benjamin Brown _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Jeffrey Benjamin Brown
-- Jeffrey Benjamin Brown
-- Jeffrey Benjamin Brown

Shouldn't that be "throwError", not "fail"?
--Will
On Tue, Dec 1, 2015 at 12:44 PM, Jeffrey Brown
I spoke too soon; I'm seeing the same problem with MonadError.
Prelude> :set -XFlexibleContexts Prelude> import Control.Monad.Except Prelude Control.Monad.Except> let f = (fail "be Left!" :: (MonadError String m) => m ()) Loading package transformers-0.4.2.0 ... linking ... done. Loading package mtl-2.2.1 ... linking ... done. Prelude Control.Monad.Except> f :: Either String () *** Exception: be Left! Prelude Control.Monad.Except>

Oops, disregard that. Other responses didn't show up for some reason.
On Tue, Dec 1, 2015 at 2:34 PM, William Yager
Shouldn't that be "throwError", not "fail"?
--Will
On Tue, Dec 1, 2015 at 12:44 PM, Jeffrey Brown
wrote: I spoke too soon; I'm seeing the same problem with MonadError.
Prelude> :set -XFlexibleContexts Prelude> import Control.Monad.Except Prelude Control.Monad.Except> let f = (fail "be Left!" :: (MonadError String m) => m ()) Loading package transformers-0.4.2.0 ... linking ... done. Loading package mtl-2.2.1 ... linking ... done. Prelude Control.Monad.Except> f :: Either String () *** Exception: be Left! Prelude Control.Monad.Except>

On Mon, 30 Nov 2015 14:25:49 -0800
Jeffrey Brown
I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
The Monad instance for (Either e) uses the default definition of 'fail', which is to throw an exception: instance Monad (Either e) where return = Right Left l >>= _ = Left l Right r >>= k = k r In general, 'Left' can't be used because that would only type check for (Either String), but the Monad instance is more general than that. -- Michael Walker (http://www.barrucadu.co.uk)

On Mon, Nov 30, 2015 at 02:25:49PM -0800, Jeffrey Brown wrote:
I've written a monadic function which in a Maybe context produces a Nothing when it fails (as intended), but in an Either context produces an Exception rather than a Left.
The Maybe instance for Monad overrides fail to be Nothing, but Either instance does not. The default definition for fail is error. The Except type has the behavior you are looking for, I believe — but you may be better off avoiding the use of fail to begin with. :) Except/ExceptT: http://haddock.stackage.org/lts-3.16/transformers-0.4.2.0/Control-Monad-Tran... Also recommended for all your error-ful needs: http://haddock.stackage.org/lts-3.16/errors-2.0.1/Control-Error.html
participants (5)
-
Bryan Richter
-
Jeffrey Brown
-
Michael Walker
-
Oleg Grenrus
-
William Yager