Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert list of Eithers to an Either with a list in it

Tags:

haskell

I am a beginner in Haskell and I am working on some Haskell code that uses Either for error handling. The left element of the Either represents an error, while the right element represents a successful result. The code often uses the Applicative instance of Either, which seems to be designed for this use case.

Given an object of type [Either e r], what is the most elegant way to turn it into an object of type Either e [r]? The point of this is that we might have an array of return values from some functions we called, and if any of those return values is an error, we want to get that error and throw away everything else. If multiple elements of the array have an error, I would prefer to get the left-most error if possible.

I was able to solve this problem myself in the code below by writing two functions, one of which is recursive, but is there a better way?

type Error = [Char]

myFunc :: [Either Error a] -> Either Error [a]
myFunc = myFunc2 []

myFunc2 :: [a] -> [Either Error a] -> Either Error [a]
myFunc2 r ((Left error):rest) = Left error
myFunc2 r ((Right item):rest) = myFunc2 (r ++ [item]) rest
myFunc2 r [] = Right r

main :: IO()
main = do
  -- This prints: Right [1, 2, 3]
  putStrLn (show (myFunc [Right 1, Right 2, Right 3]))

  -- This prints: Left "division by zero"
  putStrLn (show (myFunc [Right 1, Left "division by zero", Right 3]))
like image 595
David Grayson Avatar asked Jul 02 '16 22:07

David Grayson


2 Answers

Use sequenceA of Data.Traversable

like image 33
mariop Avatar answered Nov 13 '22 14:11

mariop


sequence from Control.Monad:

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

as in:

\> import Control.Monad (sequence)

\> sequence [Right 1, Right 2, Right 3]
Right [1,2,3]

\> sequence [Right 1, Left "division by zero", Right 3]
Left "division by zero"
like image 131
behzad.nouri Avatar answered Nov 13 '22 13:11

behzad.nouri