我正在使用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一起做到这一点?
答案 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)