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

Gus*_*ust 3 monads haskell either

考虑以下函数:

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
Run Code Online (Sandbox Code Playgroud)

有没有办法以更简洁的方式写这个?也许使用>>=运算符?

需要考虑一下,因为这里实际上有两个 monad:[]Either,虽然List这里不充当 monad,但更多的是充当Traversable

chi*_*chi 11

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

validateList :: (a -> Either e a) -> [a] -> Either e [a]
validateList = traverse
Run Code Online (Sandbox Code Playgroud)

这是traverse使用Either a应用函子和[]可遍历/可折叠。

请注意,这确实是惰性/短路:一旦Left找到 a ,就不再需要输入列表的其余部分。这是使用无限列表的测试:

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