我正在学习Haskell,并且度过了愉快的时光。我特别喜欢的一件事是使用monad错误类型在fmap或>> =中传播场景后面的错误条件。例如,在此代码中,我使用hoauth2进行身份验证的连接。它使用Either ...
定义OAuth2Resulttype OAuth2Result a = Either ByteString a -- from OAuth2
getEntries :: Manager -> AccessToken -> IO(OAuth2Result [Entry])
-- code omitted
filterResults :: [Entry] -> OAuth2Result [Entry]
filterResults = return $ filter hasUrl
printEntries :: [Entry] -> IO() -- What type can I use here?
printEntries Left l = -- code omitted
printEntries Right r = -- code omitted
main = do
entriesResult <- getEntries mgr token -- This is an OAuth2Result
let filtered = entriesResult >>= filterResults
printEntries filtered
我遇到的问题是函数有像printEntries这样的IO。在这种情况下,我必须显式模式匹配才能进行错误处理。我肯定希望能够以某种方式隐藏它,就像我使用filterResults调用一样。
我该怎么做?
谢谢!
答案 0 :(得分:1)
以下是如何使用runEitherT
进行操作,这需要一些提升和提升才能使类型正确:
import Control.Monad
import Control.Monad.Trans
import Control.Error
import Data.List (isInfixOf)
type Entry = String
type Result a = Either String a
sampleEntries = [ "good 1", "good 2", "good 3", "bad 4", "good 5", "bad 6", "good 7" ]
getEntries :: Int -> IO (Result [Entry])
getEntries n = if n >= 0 && n <= length sampleEntries
then return $ Right $ take n sampleEntries
else return $ Left $ "invalid n: " ++ show n
filterEntries :: [Entry] -> Result [Entry]
filterEntries ents = if all isGood ents
then Right $ ents
else Left "found a bad entry"
where isGood str = isInfixOf "good" str
printEntries :: [Entry] -> IO ()
printEntries ents = forM_ (zip [1..] ents) $ \(i,e) -> print (i,e)
doit n = do
ents <- (lift $ getEntries n) >>= hoistEither
filtered <- hoistEither $ filterEntries ents
lift $ printEntries filtered
main n = do result <- runEitherT $ doit n
case result of
Left e -> putStrLn $ "Error: " ++ e
Right _ -> putStrLn $ "no errors"
请注意以下行为:
main 100
失败,因为getEntries
返回错误main 4
失败,因为filterEntries
返回错误main 3
成功