简体   繁体   中英

Composing two error-raising functions in Haskell

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?

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.

First of all: if anything it should be gf , not fg 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 gb . composeMaybe should return the composition of the function with f.

这是一个关于Haskell monad的优秀教程 (特别是在第一个例子中使用的Maybe monad )。

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 fx if you want to pass that result to g .

                         case f x of
                              Nothing -> ...
                              Just y  -> ...

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, (.) fgx = f (gx) .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM