Savenkov Alexey
Savenkov Alexey

Reputation: 698

Combining (a -> Maybe a) and (a -> a) functions

I have two functions:

f :: a -> Maybe a
g :: a -> a

I want to create such function:

h :: a -> Maybe a

h x
| isJust(f x) = Just (g $ fromJust(f x))
| otherwise   = Nothing

How can I do it in more elegant way?

Upvotes: 3

Views: 186

Answers (3)

effectfully
effectfully

Reputation: 12715

Having

fmap2 :: (Functor g, Functor f) => (a -> b) -> g (f a) -> g (f b)
fmap2 = fmap . fmap

here is a funny way:

h :: a -> Maybe a
h = fmap2 g f

fmap2 g f ~> fmap (fmap g) f ~> fmap g . f ~> \x -> fmap g (f x)

The Functor ((->) r) instance is used here: fmap can be used instead of (.).

Upvotes: 5

Sibi
Sibi

Reputation: 48654

Why not simply this:

h :: a -> Maybe a
h x = fmap g (f x)

Or the operator version:

h :: a -> Maybe a
h x = g <$> f x

Upvotes: 4

Zeta
Zeta

Reputation: 105886

Since you've tagged this question with :

h :: a -> Maybe a
h = fmap g . f

For an explanation:

f            ::                          a -> Maybe a
g            ::        a ->       a
fmap g       ::  Maybe a -> Maybe a
(.)          :: (Maybe a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a)
(.) (fmap g) ::                         (a -> Maybe a) -> (a -> Maybe a)
fmap g . f   ::                                           (a -> Maybe a)
h            ::                                            a -> Maybe a

Note that (.)'s and fmap g's types are actually more general:

(.) :: (b -> c) -> (a -> b) -> (a -> c)
-- b in this case is Maybe a
-- c in this case is Maybe a

fmap g :: Functor f => f a -> f a
-- f in this case is Maybe

However, you could also pattern match on the result of f:

h x = 
  case f x of
    Just k -> Just (g k)
    _      -> Nothing

Note that your original example wouldn't even compile, since g's return type isn't correct.

Upvotes: 12

Related Questions