我想将函数f
应用于值列表,但函数f
可能会随机失败(它实际上是调用云中的服务)。
我以为我想要使用类似map
的东西,但是我想将该函数应用于列表中的所有元素,之后,我想知道哪些元素失败了,哪些元素成功了。
目前我正在使用错误对包装函数f
的响应对象,之后我可以有效unzip
即。
之类的东西 g : (a->b) -> a -> [ b, errorBoolean]
f : a-> b
然后运行代码... map g (xs)
有更好的方法吗?另一种替代方法是迭代数组中的值,然后返回一对数组,一个列出成功值,另一个列出失败。对我而言,这似乎应该是相当普遍的事情。或者,我可以返回一些特殊价值。处理这个问题的最佳做法是什么?
答案 0 :(得分:15)
如果f
正在调用云,那么f
无疑会使用某些monad,可能是IO
monad或者来自IO
monad的monad 。有map
的monadic版本。以下是您通常会做的第一次尝试:
f :: A -> IO B -- defined elsewhere
g :: [A] -> IO [B]
g xs = mapM f xs
-- or, in points-free style:
g = mapM f
如果对g
的任何调用失败,则f
将失败,并且没有返回任何值的(可能)不受欢迎的属性。我们通过使其f
返回答案或错误消息来解决此问题。
type Error = String
f :: A -> IO (Either Error B)
g :: [A] -> IO [Either Error B]
g = mapM f
如果您希望将所有错误一起返回,并且所有成功结合在一起,则可以使用lefts
中的rights
和Data.Either
函数。
h :: [A] -> IO ([B], [Error])
h xs = do ys <- g xs
return (rights ys, lefts ys)
如果您不需要错误消息,请使用Maybe B
代替Either Error B
。
Either
数据类型是表示可能导致错误或值正确的值的最常用方法。错误使用Left
构造函数,正确的值使用Right
构造函数。作为奖励,“正确”在英语中也意味着“正确”,但正确值使用Right
构造函数的原因实际上更深(因为这意味着我们可以使用修改正确的Either类型创建一个仿函数结果,这是Left
构造函数无法实现的。)
答案 1 :(得分:2)