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.