Consider the following function:
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
Is there a way to write this in a more concise way? Maybe using the >>=
operator?
A bit to think about because there are actually two monads here: []
and Either
, although List
here is not acting as a monad but just more so as a Traversable
CodePudding user response:
I believe your Traversable
idea is exactly what you need.
validateList :: (a -> Either e a) -> [a] -> Either e [a]
validateList = traverse
This is traverse
using the Either a
applicative functor and the []
traversable/foldable.
Note that this does indeed lazy/short-circuiting: as soon as a Left
is found the rest of the input list is no longer demanded. Here is a test using an infinite list:
> validateList (\n -> case n of 1 -> Right 56 ; 2 -> Left "fdsf") [1..]
Left "fdsf"