我遇到的问题是:
以类似于mapMaybe的方式,定义 功能: composeMaybe ::(a-> Maybe b) - > (b - >也许c) - > (a->也许c) 它组成了两个错误提升功能。
类型Maybe a和函数mapMaybe的编码方式如下:
data Maybe a = Nothing | Just a
mapMaybe g Nothing = Nothing
mapMaybe g (Just x) = Just (g x)
我尝试使用这样的构图:
composeMaybe f g = f.g
但它没有编译。
有人能指出我正确的方向吗?
答案 0 :(得分:7)
您正在寻找的工具已经存在。 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
当m = Maybe时,composeMaybe的实现变得明显:
composeMaybe = (>=>)
查看(>=>)
的定义,
f >=> g = \x -> f x >>= g
如果您想以自己的方式考虑
,可以内联composeMaybe f g x = f x >>= g
或者可以写成do
- 糖为:
composeMaybe f g x = do
y <- f x
g y
一般来说,我只是坚持使用(>=>)
,这有很好的理论原因,因为它提供了最简洁的方式来陈述monad定律。
答案 1 :(得分:6)
首先:如果它应该是g.f
,而不是f.g
,因为你想要一个与f相同的参数的函数,并给出与g相同的返回值。但是这不起作用,因为f的返回类型不等于g的参数类型(f的返回类型在其中有一个Maybe而g的参数类型没有)。
所以你需要做的是:定义一个以Maybe b
为参数的函数。如果该参数为Nothing
,则应返回Nothing
。如果参数为Just b
,则应返回g b
。 composeMaybe
应该使用f。
答案 2 :(得分:5)
这是一个关于Haskell monad的优秀tutorial(特别是 Maybe monad ,在第一个例子中使用)。
答案 3 :(得分:4)
composeMaybe :: (a -> Maybe b)
-> (b -> Maybe c)
-> (a -> Maybe c)
composeMaybe f g = \x ->
由于g
采用b
类型的参数,但f
生成类型为Maybe b
的值,因此您必须对{{1}的结果进行模式匹配如果要将结果传递给f x
。
g
答案 4 :(得分:3)
一个非常相似的函数已经存在 - monadic绑定运算符>>=
。它的类型(对于Maybe monad)是Maybe a -> (a -> Maybe b) -> Maybe b
,它的用法如下:
Just 100 >>= \n -> Just (show n) -- gives Just "100"
它与你的composeMaybe
函数不完全相同,它使一个函数返回Maybe而不是第一个参数的直接Maybe值。但是您可以使用此运算符非常简单地编写composeMaybe
函数 - 它几乎与普通复合函数(.) f g x = f (g x)
的定义一样简单。
答案 5 :(得分:0)
请注意composeMaybe
的参数类型与monadic绑定运算符对其后一个参数的需求有多接近:
ghci> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
f
和g
的顺序对于作文来说是倒退的,那么更好的名字呢?
thenMaybe :: (a -> Maybe b) -> (b -> Maybe c) -> (a -> Maybe c)
thenMaybe f g = (>>= g) . (>>= f) . return
鉴于以下定义
times3 x = Just $ x * 3
saferecip x
| x == 0 = Nothing
| otherwise = Just $ 1 / x
例如,可以
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