从IO转换到EitherT IO a

时间:2015-04-15 16:34:24

标签: haskell monads monad-transformers

我正在使用servant库来获取API。它运行在:EitherT (Int, String) IO a monad中。我有一个类型为IO Maybe a的函数,并希望使用它。

这是一个有效的例子:

sourcesGetAll :: EitherT (Int, String) IO [Source]
sourcesGetAll = liftIO $ sourcesList h

sourcesList :: IO [Source]

但现在我想一起使用这两个功能

sourcesFind :: IO (Maybe Source)
sourcesGetOne :: EitherT (Int, String) IO Source
sourcesGetOne = ???

我想这样做:

maybeNotFound :: Maybe a -> Either (Int, String) a
maybeNotFound Nothing = Left (404, "Not Found")
maybeNotFound Just a  = Right a

我如何与所有花哨的monad一起做到这一点?

3 个答案:

答案 0 :(得分:4)

您可以使用hoistEither :: Monad m => Either a b -> EitherT a m b来实现此目的:

maybeNotFoundT :: IO (Maybe a) -> EitherT (Int, String) IO a
maybeNotFoundT maAct = do
  ma <- liftIO maAct -- get the Maybe a. Now ma :: Maybe a
  hoistEither $ maybeNotFound ma

答案 1 :(得分:4)

您可以将其分解为两个独立的问题:

  • IO (Maybe a)转换为MaybeT IO a

  • MaybeT IO a转换为EitherT (Int, String) a

第一个是使用MaybeT构造函数解决的:

MaybeT :: IO (Maybe a) -> MaybeT IO a

第二个是使用noteT库中的errors解决的:

noteT :: Monad m => a -> MaybeT m b -> EitherT a m b

答案 2 :(得分:1)

另一个答案归功于对freenode的争吵:

sourcesGetOne = EitherT $ maybeNotFound <$> sourcesFind
  

所以问题是如何编写函数.. IO (Maybe a) -> EitherT (Int, String) IO a   给定函数f :: Maybe a -> Either (Int, String) a,然后一种方式是..

     

myFunc action = EitherT (f <$> action)

     

如果你看一下EitherT的文档 - https://hackage.haskell.org/package/either-4.3.3.2/docs/Control-Monad-Trans-Either.html。然后你会看到EitherT (Int, String) IO a实际上只是一个被包裹的IO (Either (Int, String) a)