简体   繁体   English

在Haskell中编写两个错误提升函数

[英]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. 以类似于mapMaybe的方式,定义函数:composeMaybe ::(a-> Maybe b) - >(b - > Maybe c) - >(a-> Maybe c),它组成两个错误提升函数。

The type Maybe a and the function mapMaybe are coded like this: 类型Maybe a和函数mapMaybe的编码如下:

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. Control.Monad中有两个Kleisli组合运算符。

(>=>) :: 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: 当m = Maybe时,composeMaybe的实现变得明显:

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: 或者可以用do -sugar写成:

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. 一般来说,我只是坚持使用(>=>) ,这有很好的理论原因,因为它提供了最简洁的方式来陈述monad定律。

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. 首先:如果它应该是gf ,而不是fg因为你想要一个与f相同的参数的函数,并给出与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). 但是这不起作用,因为f的返回类型不等于g的参数类型(f的返回类型中有一个Maybe而g的参数类型没有)。

So what you need to do is: Define a function which takes a Maybe b as an argument. 所以你需要做的是:定义一个以Maybe b为参数的函数。 If that argument is Nothing , it should return Nothing . 如果该参数为Nothing ,则应该返回Nothing If the argument is Just b , it should return gb . 如果参数是Just b ,它应该返回gb composeMaybe should return the composition of the function with f. composeMaybe应该用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 . 由于g采用类型b的参数,但f生成类型为Maybe b的值,因此如果要将结果传递给g ,则必须对fx的结果进行模式匹配。

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

A very similar function already exists — the monadic bind operator, >>= . 一个非常相似的函数已经存在 - monadic绑定运算符, >>= Its type (for the Maybe monad) is Maybe a -> (a -> Maybe b) -> Maybe b , and it's used like this: 它的类型(对于Maybe monad)是Maybe a -> (a -> Maybe b) -> Maybe b ,它的用法如下:

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. 它与你的composeMaybe函数不完全相同,它接受一个函数返回Maybe而不是第一个参数的直接Maybe值。 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) . 但是你可以用这个操作符非常简单地编写你的composeMaybe函数 - 它几乎和普通composeMaybe函数的定义一样简单, (.) fgx = f (gx)

Notice how close the types of composeMaybe 's arguments are to what the monadic bind operator wants for its latter argument: 请注意composeMaybe的参数类型与composeMaybe绑定运算符对其后一个参数的需求有多接近:

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? fg的顺序对于构图是向后的,那么更好的名字怎么样?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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