我正在尝试理解<=<
函数:
ghci> :t (<=<)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
根据我的理解,我给它2个函数和a
,然后我会得到m c
。
那么,为什么这个例子不编译?
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.
答案 0 :(得分:12)
这里有两个错误。
首先,如果(<=<)
共享同一个monad,Maybe
只编写monadic函数。换句话说,您可以使用它来组成两个(<=<) :: (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
修复函数的一种简单方法就是定义一个将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 . f <=< g) x
。
然后解决方案变为:
{{1}}
答案 1 :(得分:4)
请注意,在
中(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
m
是静态的 - 您正试图在定义中将[]
和Maybe
替换为m
- 这不会输入检查。
您可以使用<=<
撰写a -> m b
形式的函数,其中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"]
答案 2 :(得分:1)
你不能将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