Using Either in Haskell

I have two values t1 and t2 , of type Either String Type . Left values ​​are used to handle errors. These values ​​are used in a function that returns an Either String Type .

I want to check if t1 and t2 correspond to Right values ​​and satisfy p :: Type -> Bool . If they do, I want to return Right (the type inside t1) . If both t1 and t2 are Right values ​​but do not satisfy p , I want to return Left someString . If one of t1 or t2 is a Left value, I just want to pass that value.

How can I do this in an elegant way? I have a suspicion that using Either as a monad is the right thing, but I'm not sure how to do it.

+6
source share
4 answers

Why monads?

 test p (Right t1) (Right t2) | p t1 && p t2 = Right t1 | otherwise = Left "nope" test _ (Left t1) _ = Left t1 test _ _ (Left t2) = Left t2 
+9
source

If you want to do this with Monad , it will look something like this, but the Monad instance for Either has recently been changed, so this does not actually work in recent GHCs:

 do v1 <- t1 v2 <- t2 guard (p v1 && p v2) `mplus` Left someString return v1 
+5
source

You can create your own error data type and make it an instance of Monad.

 data Computation a = Error String | Result a instance Monad Computation where (Result x) >>= k = kx e@ (Error a) >>= k = e 

And then use the method described by Ganesh Sittampalam . (You also need to add an instance of MonadPlus Computation.

Refresh for completeness, it will look like this:

 import Control.Monad data Computation a = Error String | Result a instance Monad Computation where return a = Result a (Result x) >>= k = kx (Error a) >>= k = Error a instance MonadPlus Computation where mzero = Error "Always fail" mplus (Error a) r = r mplus l _ = l check :: (Int -> Bool) -> Computation Int check p = do v1 <- Result 4 v2 <- Result 2 guard (p v1 && p v2) `mplus` Error "someString" return v1 
+3
source

You can distinguish a monadic action from the distribution of Left values ​​if you really want to:

 import Control.Monad import Control.Applicative import Control.Monad.Instances 

This gives a simple monadic action:

 foo :: Type -> Type -> Either String Type foo t1 t2 | p t1 && p t2 = Right t1 | otherwise = Left somestring 

What can you apply to monadic arguments to get the desired function using

 fooM :: Either String Type -> Either String Type -> Either String Type fooM t1 t2 = join (foo <$> t1 <*> t2) 

or equivalent

 fooM t1 t2 = do a <- t1 b <- t2 foo ab 
+1
source

Source: https://habr.com/ru/post/890127/


All Articles