iluvAS
iluvAS

Reputation: 513

Mapping a functor to another in Haskell

I have a function that produces a Maybe a type and I'm using it in a function to produce an Either b a. Is there a way I can map Nothing to Left x to simplify my code? The following code gives some context:

rmX :: ... -> Maybe a
cvX :: ... -> Either CVXError a
data CVXError = BadIndex | NoCover | NoSpace
cvX ... =
  ...
  case rmx 1 xs of
    Nothing -> Left NoSpace
    Just p  -> Right (x2:x1:(fromJust (rmX (-1) p)))
-- given that rmX always passes on negative value arg

The case statement is just begging to be replaced with fmap but the problem is that I'm not sure how to 'map' Nothing to Left NoSpace in an fmap call or to even extract this pattern to make my own util function.

Upvotes: 2

Views: 223

Answers (3)

chepner
chepner

Reputation: 531625

One similar option is to use the Maybe monad until the very end, then apply Left or Right as necessary with maybe.

maybe (Left NoSpace) Right $ do
     p1 <- rmX 1 xs
     p2 <- rmX (-1) p1
     return (x2:x1:p2)

There's lots of room for tweaking this, depending on your preference for do notation vs >>=:

-- untested; take these with a grain of salt...

maybe (Left NoSpace) Right $ do
    p <- rmX 1 xs >>= rmX (-1) 
    return (x2:x1:p)

maybe (Left NoSpace) Right (rmX 1 xs >>= rmX (-1) >>= (return . (x1:)) >>= (return . (x2:)))

-- etc

Upvotes: 0

duplode
duplode

Reputation: 34388

In this context, it is worth mentioning the errors package. It offers a number of functions for juggling Maybe, Either and related types, including note, which "[tags] the Nothing value of a Maybe":

note :: a -> Maybe b -> Either a b
cvX ... =
  ...
  note NoSpace $ fmap (\p -> x2:x1:(fromJust (rmX (-1) p))) (rmX 1 xs)

Unsurprisingly, the implementation of note uses maybe exactly like Sebastian Redl's answer does.

P.S.: It is always a little unpleasant to use fromJust, given how it fails when given Nothing. If rmX (-1) cannot produce a Nothing, you might want to consider factoring out a separate function that doesn't return Maybe a to be used instead of fromJust (rmX (-1) p).

Upvotes: 4

Sebastian Redl
Sebastian Redl

Reputation: 72019

You're looking for the maybe function:

cvX ... =
  ...
  maybe (Left NoSpace) (\p -> Right (x2:x1:(fromJust (rmX (-1) p)))) $
    rmX 1 xs

Upvotes: 6

Related Questions