fn返回m(Either)over map参数的mapM以嵌套的Eithers结束

时间:2015-12-02 22:44:55

标签: haskell

应用程序将用户输入作为参数(比如可能是数字ID的文本)。 然后我们想要例如使用该ID从数据库中获取内容。 这两个操作都可能失败(所以我们到达Either)并且都涉及与外部世界的交互(所以IO)。

将monadic动作映射到某个结构 - mapM,简单!

type E1 = Either String Int 

fetchFromDb :: Int -> IO E1 
fetchFromDb i = do   
    return $ case (i `mod` 2 == 0) of 
        True  -> Left "Error - evens not allowed" 
        False -> Right (100 + i) 

main :: IO () 
main = do 
    n1 <- fetchFromDb 1 
    n2 <- fetchFromDb 2 
    n3 <- mapRight fetchFromDb ((Right 3)::E1) 
    n4 <- mapM fetchFromDb ((Right 4)::E1) 
    n5 <- mapM fetchFromDb ((Left "No Int at all")::E1) 
    putStrLn $ "n1 = " ++ (show n1) 
    putStrLn $ "n2 = " ++ (show n2) 
    putStrLn $ "n3 = " ++ (show n3)
    putStrLn $ "n4 = " ++ (show n4)
    putStrLn $ "n5 = " ++ (show n5)

n1 = Right 101
n2 = Left "Error - evens not allowed"
n3 = Right (Right 103)
n4 = Right (Left "Error - evens not allowed")
n5 = Left "No Int at all"

如上所示 - 如果用户提供了错误的Int,我们会收到您期望的Left错误。如果我们有一个有效的Int虽然Either嵌套了(一旦我想到Monad的{​​{1}}实例定义有意义了。)

所以 - 需要进行某种减少或折叠,但我不能完全看到如何将它连接起来以及我的初始值是什么。

脚注:在这种情况下,我当然可以使用合适的Either表达式简单地提取所需的Int,但我正在查看几个参数。

1 个答案:

答案 0 :(得分:4)

你有两种方法来处理它。第一种是使用EitherT而不是Either,因此您可以将其用作monad。这样您就可以编写monadic代码,Either's将合并为一个。

第二个(更简单地引入现有代码)使用Control.Monad.join :: Monad m => m (m a) -> m a,对于嵌套monad(如Eithers),它只给你一个。