我有一个函数接受一些参数并返回IO (Either String String)
,比如说
testEither :: Int -> IO (Either String String)
testEither 0 = return (Left "we got an error")
testEither _ = return (Right "everything is ok")
(真实函数从现实世界中获取一些东西并可能失败)
我想将该函数的输出发送到writeFile fileName
。预期的行为:如果我将testEither 0
绑定到writeFile "test.txt"
,则会导致Left ...
失败,如果我使用testEither 1
调用它,我会在文件{{everything is ok
中找到test.txt
1}}。
我猜整个表达式的类型应该类似IO (Either String ())
,但我可能错了。
答案 0 :(得分:3)
使用Either
Traversable
实例
import Data.Traversable
main = do
traverse (writeFile "test.txt") (Left "we got an error")
traverse (writeFile "test.txt") (Right "everything is ok")
答案 1 :(得分:3)
您可以使用ErrorT 1 monad转换器在IO
monad之上为您提供纯错误处理:
import Control.Monad.Error
testEither :: Int -> IO (Either String String)
testEither 0 = return (Left "we got an error")
testEither _ = return (Right "everything is ok")
main = runErrorT $ do
result <- ErrorT $ testEither 0
lift $ writeFile "test.txt" result
1 ErrorT
似乎已在mtl
的最新版本中替换为ExceptT
,但功能应该类似。子>
答案 2 :(得分:1)
这不会自动发生,但您可以轻松地使用模式匹配来执行此操作:
writeFileEither :: FilePath -> Either a String -> IO ()
writeFileEither _ (Left _) = return ()
writeFileEither fp (Right text) = writeFile fp text
然后你可以用
将它们绑定在一起main = testEither 1 >>= writeFileEither "test.txt"
或者用符号表示:
main = do
result <- testEither 1
writeFileEither "test.txt" result
答案 3 :(得分:0)
下面的main
函数是一个示例,说明如何在testEither
中使用IO
:如果testEither
返回错误,则会将错误写入{{1}否则从stderr
中提取正确的结果并将其写入文件Right
:
test.txt