On Tuesday 17 May 2011 01:40:41, Gracjan Polak wrote: > Daniel Fischer <daniel.is.fischer <at> googlemail.com> writes: > > On Monday 16 May 2011 23:41:44, Gracjan Polak wrote: > > > Thanks Daniel, Yves and Edward for explanation. Two things come to > > > my mind now. > > > > > > 1. It should be unified. > > > > The (Either e) Monad instance was recently changed after people have > > long complained that there shouldn't be an (Error e) constraint. > > It's unlikely that that will be reverted soon. > > I did not request a revert, I asked about consistent behavior. >
Not directly, but for ghci> fail "msg" :: Either String Int and ghci> runIdentity (runErrorT (fail "msg")) :: Either String Int to have the same behaviour, there are three possibilities a) change ErrorT's behaviour, so that the latter matches the former. b) change (Either e)'s Monad instance so that the former matches the latter. c) change both. b) is the most reasonable, IMO, and that's reverting the change of the Monad instance of (Either e). > > It's the (Error e) Monad which adds the structure [nowadays, Error e = > > ErrorT e Identity]. Misremembered, there never was a newtype doing for ErrorT what State does [did] for StateT etc. > > I do not understand this part. Can you elaborate? > You wrote: "... Should be the same as Identity monad should not add structure." Now, the Identity Monad doesn't add the structure that makes the former result in (Left "msg"), Prelude Control.Monad.Identity> runIdentity (fail "msg") :: Either String Int *** Exception: msg The Monad instance that makes fail not be error is instance (Monad m, Error e) => Monad (ErrorT e m) where ... > > > 2. I need a Failure monad that works well with pattern match > > > failures > > > > > > (that call fail). I'd like to use it like this: > > > runErrorT $ do > > > > > > Active <- getStatus -- ensure proper status > > > Just elm <- lookup stuff there -- lookup element > > > when (condition) $ fail "wrong!" -- check condition > > > return 1234 -- return useful value > > > > > > sort of... > > > > That does work, doesn't it? > > Indeed this does work, but it is fragile wrt refactorings. > > Suppose we have the code: > > result <- runErrorT $ do > lift $ print "was here" > fail "msg" > > (result = Left "msg") > > after a while the print statement may be removed: > > result <- runErrorT $ do > fail "msg" > > (result = Left "msg") > > and then somebody will see that inner 'do' does not depend on outer > monad But the transformation result <- runWhatEver stuff to let result = stuff generally doesn't typecheck, so it can't be generally correct, hence if it typechecks, one has to examine each case to decide where it's valid and where not. One big point of ErrorT is the working around the inner Monad's fail, so it should be a big warning sign if a `fail' appears. > so next refactoring will be: > > let result = do > fail "msg" > > (result = error "msg") > > And here code breaks... > > > Roll your own, > > That is a good idea. I looked also at Attempt. > > Thanks for responses. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe