短路列表,一种 `(a -> Either e a) -> [a] -> Either e [a]` 类型的...单子操作?

3

请考虑下面的函数:

validateList :: (a -> Either e a) -> [a] -> Either e [a]
validateList validate []     = Right []
validateList validate (x:xs) =
    case validate x of
      Left err -> Left err
      Right y  -> case validateList validate xs of
                    Left err -> Left err
                    Right ys -> Right $ y:ys

有没有更简洁的写法?或许可以使用 >>= 运算符吗?
需要思考一下,因为这里实际上有两个单子: []Either,尽管 List 在这里不是作为一个单子而更像是一个 Traversable
1个回答

11

我相信你的Traversable想法恰好是你所需要的。

validateList :: (a -> Either e a) -> [a] -> Either e [a]
validateList = traverse

使用 Either a 函子和 [] 可遍历/折叠器来进行 traverse。请注意,这确实是惰性/短路的:一旦找到 Left,则不再需要输入列表的其余部分。以下是使用无限列表进行测试的示例:

> validateList (\n -> case n of 1 -> Right 56 ; 2 -> Left "fdsf") [1..]
Left "fdsf"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接