简体   繁体   中英

Monadic function of `(a -> m (Either e b)) -> Either e a -> m (Either e b)`?

Is there a way to write this function in a more "monadic" way, instead of resorting to pattern matching on Either ?

{-# LANGUAGE LambdaCase #-}

calculate :: (Monad m) => (a -> m (Either e b)) -> Either e a -> m (Either e b)
calculate f = \case
  Left err   -> return $ Left err
  Right vals -> f vals

Specifically, for my use case, m is IO ; f is a function that takes in input and produces some IO effect or fails, and the input is something that could have failed already.

Maybe using ExceptT ?

Yep, looks like ExceptT to me. Though I would probably not use a function with this signature -- instead, I would use ExceptT more broadly, and then this function is just (=<<) . Of course this is guesswork based on the use case.

But if you must:

calculate :: (Monad m) => (a -> m (Either e b)) -> Either e a -> m (Either e b)
calculate f m = runExceptT (ExceptT . f =<< ExceptT m)

You can use traverse and join :

calculate :: (Monad f, Traversable f, Applicative m) => (a1 -> m (f a2)) -> f a1 -> m (f a2)
calculate f e = join <$> traverse f e

Note the more general type signature. That's what GHC infers. Instead of Either e any type is sufficient as long as it has instances for Monad and Traversable . Also, m doesn't need to have a Monad , Applicative is enough.

ExceptT works as well (the first one doesn't change the type of the result, the second one goes all in on ExceptT ):

calculate :: (Monad m) => (a -> ExceptT e m b) -> Either e a -> m (Either e b)
calculate f e = runExceptT $ ExceptT (pure e) >>= f

calculate2 :: (Monad m) => (a -> ExceptT e m b) -> Either e a -> ExceptT e m b
calculate2 f e = ExceptT (pure e) >>= f

I personally would prefer the former, because I find it easier to grasp without ExceptT .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM