Mapping an Either list to integers

134 Views Asked by At

I am trying to do the following:

processRights :: [Either a Int] -> Int
processRights xs = map (\Right x -> x, \Left x -> 0) xs

So, xs is a [Either a Int], and I wish to produce a mapped list of the same length where for each int there is the same int, 0 otherwise.

How can I acomplish that?

3

There are 3 best solutions below

4
FrederikVds On BEST ANSWER

You can use the either, id and const functions:

processRights :: [Either a Int] -> [Int]
processRights = map $ either (const 0) id

either runs the first function for any Left, the second function for any Right.

id returns its argument.

const ignores its second argument and returns its first argument, its intended use is that e.g. const 0 becomes a function that ignores its argument and just returns 0.

1
willeM_ Van Onsem On

A clear way to do this is to work with a helper function. Indeed:

processRights :: [Either a Int] -> [Int]
processRights = map go
    where go (Right x) = x
             (Left _) = 0

This is not the most concise way, but it shows what is happening. You can simplify this with fromRight :: b -> Either a b -> b where we provide a value to use or a Left x element, and it will thus either select that value, or the value wrapped in the Right data constructor, so:

import Data.Either(fromRight)

processRights :: Num b => [Either a b] -> [b]
processRights = map (fromRight 0)
0
Daniel Wagner On

Your proposed code is really, really close, actually! Here's a working version with minimal changes:

processRights xs = map (\case Right x -> x; Left x -> 0) xs

You will need to turn on the LambdaCase language extension. (And of course, as mentioned in other answers, there are more idiomatic ways to achieve this effect.)