“ `(a -> m (Either e b)) -> Either e a -> m (Either e b)` 的单子函数是什么?”

3

有没有更“monadic”的方法来编写这个函数,而不是诉诸于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

具体而言,对于我的用例,mIOf 是一个接受输入并产生一些 IO 效果或失败的函数,并且输入可能已经失败了。也许可以使用 ExceptT
2个回答

5

是的,看起来像是 ExceptT。但我可能不会使用此签名的函数 - 相反,我更倾向于更广泛地使用 ExceptT,然后这个函数只是 (=<<)。当然,这是根据使用情况的猜测。

但如果你一定要:

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

4
您可以使用traversejoin:
calculate :: (Monad f, Traversable f, Applicative m) => (a1 -> m (f a2)) -> f a1 -> m (f a2)
calculate f e = join <$> traverse f e

注意这个更通用的类型签名,这是 GHC 推导出来的。任何具有 MonadTraversable 实例的类型都足够,而不是像 Either e 那样限定特定类型。另外,m 不需要是一个 Monad,只要有 Applicative 就可以了。 ExceptT 也可以使用(第一个不改变结果类型,第二个完全使用 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

就我个人而言,我更喜欢前者,因为我觉得没有 ExceptT 更容易理解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接