Composing two error-raising functions in Haskell
我所遇到的问题是这样的:
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.
类型Maybe a和函数mapMaybe的编码如下:
1 2 3 4
| data Maybe a = Nothing | Just a
mapMaybe g Nothing = Nothing
mapMaybe g (Just x ) = Just (g x ) |
我尝试使用这样的合成:
但是不会编译。
有人能指出我正确的方向吗?
- 如果别人为您做功课,您将如何学习?
-
我要的是指针而不是答案
您要寻找的工具已经存在。 Control.Monad中有两个Kleisli合成运算符。
1 2
| (>=>) :: 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的实现变得显而易见:
查看(>=>),
的定义
1
| f >=> g = \\x -> f x >>= g |
如果您想以自己的方式考虑,可以内联为
1
| composeMaybe f g x = f x >>= g |
或可以在do -sugar中写为:
1 2 3
| composeMaybe f g x = do
y <- f x
g y |
通常,我只会坚持使用(>=>),它具有存在的理论上很好的理由,因为它提供了陈述monad法则的最简洁的方法。
-
我猜这是家庭作业,在这种情况下,使用> =>可能不算是有效的解决方案。 :-)
-
是的,这是我昨天进行的考试的修订,我们没有介绍单子,但明年可能会在高级函数式编程中使用它们!因此仍然会派上用场! :)
-
马丁(Martijn),是的,这就是为什么我将其破解以查看其推导的原因。
首先:如果应该为g.f,而不是f.g,因为您想要一个函数,该函数具有与f相同的参数,并具有与g相同的返回值。但是,这是行不通的,因为f的返回类型不等于g的参数类型(f的返回类型中包含Maybe,而g的参数类型却不)。
因此,您需要做的是:定义一个以Maybe b作为参数的函数。如果该参数为Nothing,则应返回Nothing。如果参数为Just b,则应返回g b。 composeMaybe应该返回带有f的函数的组成。
- 嘿,谢谢你帮助一个家伙! :PI从您的回复中得出以下信息:g ::也许b->也许bg Nothing = Nothing g(Just x)= g(x)但是它说=不能构造无限类型:b =也许b compose也许b)->(b->也许c)->(a->也许c)compose也许fg = gf但它不能编译
-
a)辅助功能的签名应该为Maybe b -> Maybe c,因为g的类型为b -> Maybe c。 b)您一定不能调用辅助函数g,因为提供给composeMaybe的第二个函数已经被调用g。 c)您应该在composeMaybe的定义内定义辅助函数,以便它可以访问函数g(或者可以接受函数g作为参数)。
这是有关Haskell monad(尤其是在第一个示例中使用的Maybe monad)的出色教程。
-
sepp2k,您可能想查看本教程。您所描述的正是Maybe monad的Kleisli合成函数。看一下Control.Monad模块。
-
该链接不再有效,现在可以在这里找到:wiki.haskell.org/All_About_Monads
1 2 3 4
| composeMaybe :: (a -> Maybe b )
-> (b -> Maybe c )
-> (a -> Maybe c )
composeMaybe f g = \\x -> |
由于g接受类型为b的参数,但是f产生类型为Maybe b的值,因此如果要将结果传递给f x,则必须对f x的结果进行模式匹配。 x8>。
1 2 3
| case f x of
Nothing -> ...
Just y -> ... |
一元绑定操作符>>=已经存在一个非常相似的函数。其类型(对于Maybe monad)为Maybe a -> (a -> Maybe b) -> Maybe b,其用法如下:
1 2
| Just 100 >>= \
-> Just (show n ) -- gives Just"100" |
它与您的composeMaybe函数并不完全相同,后者需要一个函数返回Maybe而不是其第一个参数的直接Maybe值。但是您可以使用此运算符非常简单地编写composeMaybe函数,"它几乎与普通compose函数的定义(.) f g x = f (g x)一样简单。
请注意composeMaybe的参数类型与monadic绑定运算符对其后一个参数想要的距离有多近:
1 2
| ghci > :t (>>=)
(>>=) :: (Monad m ) => m a -> (a -> m b ) -> m b |
f和g的顺序对于组合而言是向后的,那么更好的名称呢?
1 2
| thenMaybe :: (a -> Maybe b ) -> (b -> Maybe c ) -> (a -> Maybe c )
thenMaybe f g = (>>= g ) . (>>= f ) . return |
给出以下定义
1 2 3 4 5
| times3 x = Just $ x * 3
saferecip x
| x == 0 = Nothing
| otherwise = Just $ 1 / x |
例如,
1 2 3 4 5 6 7 8 9 10
| 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 |