views:

147

answers:

6

The problem I have been given says this:

In a similar way to mapMaybe, define the function: composeMaybe :: (a->Maybe b) -> (b -> Maybe c) -> (a-> Maybe c) which composes two error-raising functions.

The type Maybe a and the function mapMaybe are coded like this:

data Maybe a = Nothing | Just a

mapMaybe g Nothing = Nothing
mapMaybe g (Just x) = Just (g x)

I tried using composition like this:

composeMaybe f g = f.g

But it does not compile :/

Could anyone point me in the right direction?

Chris

+6  A: 

First of all: if anything it should be g.f, not f.g because you want a function which takes the same argument as f and gives the same return value as g. However that doesn't work because the return type of f does not equal the argument type of g (the return type of f has a Maybe in it and the argument type of g does not).

So what you need to do is: Define a function which takes a Maybe b as an argument. If that argument is Nothing, it should return Nothing. If the argument is Just b, it should return g b. composeMaybe should return the composition of the function with f.

sepp2k
Hey, thanks for helping a guy out! :P I made this from your reply:g :: Maybe b -> Maybe bg Nothing = Nothingg (Just x) = g(x) But it says = cannot construct infinite type : b = Maybe bcomposeMaybe :: (a->Maybe b) -> (b -> Maybe c) -> (a-> Maybe c)composeMaybe f g = g.f but it doesn't compile
ChrisMacDee
a) The signature of the auxilarry function should be `Maybe b -> Maybe c` because the type of g is `b -> Maybe c`. b) You must not call the auxillary function g because the second function supplied to composeMaybe is already called g. c) You should define the auxillary function within the definition of composeMaybe, so that it has access to the function g (alternatively it could accept the function g as an argument).
sepp2k
+5  A: 

Here is an excellent tutorial about Haskell monads (and especially the Maybe monad, which is used in the first examples).

3lectrologos
sepp2k, you may want to check out this tutorial. What you describe is exactly the Kleisli composition function for the Maybe monad. Take a look at the Control.Monad module.
Thiago Arrais
+4  A: 
composeMaybe :: (a -> Maybe b)
             -> (b -> Maybe c)
             -> (a -> Maybe c)
composeMaybe f g = \x ->

Since g takes an argument of type b, but f produces a value of type Maybe b, you have to pattern match on the result of f x if you want to pass that result to g.

                         case f x of
                              Nothing -> ...
                              Just y  -> ...
jleedev
+3  A: 

A very similar function already exists — the monadic bind operator, >>=. Its type (for the Maybe monad) is Maybe a -> (a -> Maybe b) -> Maybe b, and it's used like this:

Just 100 >>= \n -> Just (show n) -- gives Just "100"

It's not exactly the same as your composeMaybe function, which takes a function returning a Maybe instead of a direct Maybe value for its first argument. But you can write your composeMaybe function very simply with this operator — it's almost as simple as the definition of the normal compose function, (.) f g x = f (g x).

Chuck
+3  A: 

The tool you are looking for already exists. There are two Kleisli composition operators in Control.Monad.

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c

When m = Maybe, the implementation of composeMaybe becomes apparent:

composeMaybe = (>=>)

Looking at the definition of (>=>),

f >=> g     = \x -> f x >>= g

which you can inline if you want to think about it in your own terms as

composeMaybe f g x = f x >>= g

or which could be written in do-sugar as:

composeMaybe f g x = do 
    y <- f x
    g y

In general, I'd just stick to using (>=>), which has nice theoretical reasons for existing, because it provides the cleanest way to state the monad laws.

Edward Kmett
I'm guessing this is homework, in which case using >=> probably doesn't count as a valid solution. :-)
Martijn
yeah it was revision for an exam i had yesterday, we didn't cover monads but will probably do them in the advanced functional programming next year! So still will come in handy! :)
ChrisMacDee
Martijn, true, thats why I cracked it open to take a look at the derivation.
Edward Kmett
A: 

Notice how close the types of composeMaybe's arguments are to what the monadic bind operator wants for its latter argument:

ghci> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

The order of f and g is backward for composition, so how about a better name?

thenMaybe :: (a -> Maybe b) -> (b -> Maybe c) -> (a -> Maybe c) 
thenMaybe f g = (>>= g) . (>>= f) . return

Given the following definitions

times3 x = Just $ x * 3

saferecip x
  | x == 0 = Nothing
  | otherwise = Just $ 1 / x

one can, for example,

ghci> saferecip `thenMaybe` times3 $ 4
Just 0.75
ghci> saferecip `thenMaybe` times3 $ 8
Just 0.375
ghci> saferecip `thenMaybe` times3 $ 0
Nothing
ghci> times3 `thenMaybe` saferecip $ 0
Nothing
ghci> times3 `thenMaybe` saferecip $ 1
Just 0.3333333333333333
Greg Bacon