4
\$\begingroup\$

Suppose you have an IO (Either String (String, [Int])) and you want to filter the [Int].

Let's say we want to use the following filter:

:t filter even
Integral a => [a] -> [a]

As far as I understand we need to lift the function filter even to be applied to an IO (Either String, (String, [Int])), so I did:

:t (fmap . fmap . fmap . filter) even
(Functor f1, Functor f2, Functor f3, Integral a) => f1 (f2 (f3 [a])) -> f1 (f2 (f3 [a]))

I know this symbol exists <$$$> (take a look here), but I don't want to add that dependency.

Here is the full example:

--- You can paste this in GHCi
ioe = pure $ Right ("a,b,c,d", [1,2,3,4]) :: IO (Either String (String, [Int]))
(fmap . fmap . fmap . filter) even ioe
-- return: Right ("a,b,c,d",[2,4])

It works, but I wonder: is there a better way to do it?

\$\endgroup\$
5
\$\begingroup\$

While (fmap . fmap . fmap . filter) even is certainly possible, there is a function for Either in Control.Arrow called right. The same module also contains second, which works on the second part of a pair.

right  :: (b -> c) -> Either a b -> Either a c`
second :: (b -> c) ->     (a, b) ->     (a, c)

The actual types use Arrow or ArrowChoice, but it basically boils down to this. With those functions, you can write (fmap . fmap . fmap . filter) even ioe as

(right . second . filter) even <$> ioe
-- or
(fmap . right . second . filter) even ioe

However, the behavior doesn't differ from your original variant.

Note that there are several libraries that provide lenses and enable you to write code in a similar way.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.