Haskell IO上的快速失败[字符串]
给定一个表示电子邮件列表的Haskell IO上的快速失败[字符串],haskell,Haskell,给定一个表示电子邮件列表的IO[String]: λ: let emails = return ["foo@bar.com", "bip@bap.net"] :: IO [String] 以及自动删除电子邮件失败的功能: λ: let deleteEmail email = return $ Left "failed" :: IO (Either String ()) 然后我研究了如何针对列表中的每封电子邮件尝试删除每封电子邮件。但是,当一封电子邮件无法删除时,我希望停止,即类似于序列的行为
IO[String]
:
λ: let emails = return ["foo@bar.com", "bip@bap.net"] :: IO [String]
以及自动删除电子邮件失败的功能:
λ: let deleteEmail email = return $ Left "failed" :: IO (Either String ())
然后我研究了如何针对列表中的每封电子邮件尝试删除每封电子邮件。但是,当一封电子邮件无法删除时,我希望停止,即类似于序列
的行为
λ: do { e <- emails; _ <- deleteEmail e; return e }
["foo@bar.com","bip@bap.net"]
λ: do { e <- emails; result <- deleteEmail e; return result }
Left "failed"
λ:do{e有很多选择,但我会按照我的偏好顺序看其中三个
- 使用
EitherT
transformer overIO
而不是IO(任一a)
(您需要安装任一
软件包)
- 使用
IO
的Monad
实例中的fail
抛出一个异常
另一个答案表明,您可以使用ExceptT
或EitherT
单子转换器。ExceptT
表示一个或以及一个基本单子(在本例中为IO),在该单子中,您可以使用提升评估动作。因为EihterT
形成单子(因此适用)您可以使用序列
组合删除所有电子邮件,并在第一次失败时失败,例如:
import Control.Monad.Trans.Except
import Control.Monad.IO.Class (liftIO)
import Data.Foldable (sequence_)
getEmails :: IO [String]
getEmails = return ["foo@bar.com", "bip@bap.net", "something@example.com"]
deleteEmail :: String -> ExceptT String IO ()
deleteEmail email = do
liftIO $ putStrLn ("Deleting " ++ email)
if (isPrefixOf "bip" email)
then throwE email
else return ()
deleteAllEmails :: [String] -> ExceptT String IO ()
deleteAllEmails = sequence_ . map deleteEmail
doDelete :: [String] -> IO ()
doDelete emails = do
e <- runExceptT $ deleteAllEmails emails
case e of
Left err -> putStrLn $ "Failed: " ++ err
Right _ -> putStrLn "success!"
import Control.Monad.Trans.Except
导入控制.Monad.IO.Class(liftIO)
导入数据。可折叠(序列)
getEmails::IO[字符串]
getEmails=返回[“foo@bar.com", "bip@bap.net", "something@example.com"]
deleteEmail::String->Except字符串IO()
deleteEmail=do
liftIO$putStrLn(“删除”++电子邮件)
如果(isPrefixOf“bip”电子邮件)
然后通过电子邮件
否则返回()
deleteAllEmails::[String]->字符串IO()除外
deleteAllEmails=序列\映射deleteMail
Dodelite::[String]->IO()
doDelete电子邮件=do
e putStrLn$“失败:”++错误
右->putStrLn“成功!”
您可能还想考虑使用<代码>字符串而不是<代码>字符串()/代码>和相应的<代码> MaybeT < /代码>转换器。
表达式“>代码> do.{另一件事是<代码> e <代码>实际上并不是指单个电子邮件,而是整个列表。使用时自动“拆分”您可以在transformers中使用ExceptT
(这很可能已经是一种依赖关系)代替EitherT
。嗨,巴特克-你能用一些代码示例来补充你的答案吗?我不熟悉monad transformers。谢谢编辑-第三个选项,抛出异常
不是惯用的,是吗?@KevinMeredith我当然更喜欢ExceptT
而不是throwIO
(不要在IO
中使用throw
!);但是有时候例外情况正是医生所要求的,所以我不认为我会认可“throwIO
不是惯用的”。我可能会被说服认可”throw
不是惯用的“。上次我检查了Haskell中至少有7种处理错误的方法,我不知道在IO
monad中是否有任何一种被认为是“非惯用的”fail
,最后也抛出了一个异常,并且由于其他原因有些不推荐。我使用的唯一原因是…()
是指..
可以是ADT。使用可能字符串的无
大小写可能无法提供或的含义(除非或与之一起使用)。注意-我知道我使用了字符串,但它不是ADT。