[英]Composing Monadic Functions with `<=<`
我正在尝试理解<=<
函数:
ghci> :t (<=<)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
据我了解,我给它2个函数和a
,然后我会得到一个mc
。
那么,为什么这个例子不编译?
import Control.Monad
f :: a -> Maybe a
f = \x -> Just x
g :: a -> [a]
g = \x -> [x]
foo :: Monad m => a -> m c
foo x = f <=< g x
对于foo 3
,我希望Just 3
因此。
但我得到这个错误:
File.hs:10:15:
Couldn't match expected type `a0 -> Maybe c0'
with actual type `[a]'
In the return type of a call of `g'
Probable cause: `g' is applied to too many arguments
In the second argument of `(<=<)', namely `g x'
In the expression: f <=< g x Failed, modules loaded: none.
这里有两个错误。
首先, (<=<)
只有在共享同一个monad时才编写monadic函数。 换句话说,你可以用它来组成两个Maybe
函数:
(<=<) :: (b -> Maybe c) -> (a -> Maybe b) -> (a -> Maybe c)
......或两个列表功能:
(<=<) :: (b -> [c]) -> (a -> [b]) -> (a -> [c])
...但你不能编写一个列表函数,也许这样就可以了。 这样做的原因是当你有这样的类型签名时:
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
...编译器将确保所有m
必须匹配。
第二个错误是你忘了为你的作文加上括号。 你可能想要的是这个:
(f <=< g) x
...如果省略括号,编译器会将其解释为:
f <=< (g x)
修复函数的一种简单方法就是定义一个将Maybe
s转换为列表的辅助函数:
maybeToList :: Maybe a -> [a]
maybeToList Nothing = []
maybeToList (Just a) = [a]
这个函数实际上有以下两个很好的属性:
maybeToList . return = return
maybeToList . (f <=< g) = (maybeToList . f) <=< (maybeToList . g)
...如果你将(maybeToList .)
视为类似于fmap
并将(<=<)
视为类似于(.)
并return
类似于id
那么这些是(maybeToList .)
函数法则。
然后解决方案变为:
(maybeToList . f <=< g) x
请注意,在
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
m
是静态的 - 你试图在定义中用[]
和Maybe
替换m
- 这不会进行类型检查。
您可以使用<=<
来组成形式a -> mb
函数,其中m
是单个 monad。 请注意,您可以使用不同的类型参数,但不需要将其约束为多态a
。
以下是使用此模式约束到列表monad的示例:
f :: Int -> [Int]
f x = [x, x^2]
g :: Int -> [String]
g 0 = []
g x = [show x]
λ> :t g <=< f
g <=< f :: Int -> [String]
λ> g <=< f $ 10
["10","100"]
你不能把monad混合在一起。 当你看到签名
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
Monad m
只有一个Monad,而不是两个不同的Monad。 如果是,签名就像是
(<=<) :: (Monad m1, Monad m2) => (b -> m2 c) -> (a -> m1 b) -> a -> m2 c
但实际情况并非如此,实际上通常不可能实现。 你可以做点什么
f :: Int -> Maybe Int
f 0 = Just 0
f _ = Nothing
g :: Int -> Maybe Int
g x = if even x then Just x else Nothing
h :: Int -> Maybe Int
h = f <=< g
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.