我正在尝试从其中一个博客中获取一些代码段,然后我注意到以下代码
f :: Int -> [Int]
f x = [1+x,2*x]
test :: IO ()
test = putStrLn . show $ return 5 >>= f >>= f
执行时我得到了[7,12,11,20]。为什么第二个'f'函数调用不是抛出类型错误?它与List Monad有关吗?
答案 0 :(得分:6)
这正是因为列表是monad。
return 5 >>= f >>= f
在列表monad中(>>=) = flip concatMap
,这与
concatMap f $ concatMap f $ return 5
同样在列表monad return x = [x]
中,我们有
concatMap f $ concatMap f [5]
现在,concatMap g x = concat (map g x)
,我们可以将其扩展为
concat $ map f $ concat $ map f [5]
并评估它
concat $ map f $ concat $ [[6, 10]]
concat $ map f $ [6, 10]
concat $ [[7, 12], [11, 20]]
[7, 12, 11, 20]
这有意义吗?
答案 1 :(得分:4)
让我们问一下GHC对某些子表达式的类型是什么。
> :t putStrLn . show
putStrLn . show :: (Show a) => a -> IO ()
这肯定和预期的一样。
> :t return 5 >>= f >>= f
return 5 >>= f >>= f :: [Int]
我想我们已经预料到了,但它没有回答你的问题。接下来,快速提醒该表达式如何解析:
> :i (>>=)
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
...
infixl 1 >>=
好吧,它是关联的,所以表达式是(return 5 >>= f) >>= f
。
> :t return 5 >>= f
return 5 >>= f :: [Int]
将此与(>>=)
的上述类型签名相比较,我们可以观察到两件事:
(>>=)
的第二个参数必须返回某种monad (>>=)
的第一个参数必须是同一个monad中的值因此,我们知道f
必须在此处显示类似(a -> m b)
的类型,f
的实际类型签名为Int -> [Int]
。所以我们可以手动组合这些类型:
a
= Int
b
= Int
m
= []
请注意,([] a)
与[a]
的含义相同。
所以monad确实是monad的名单。那是怎么回事?
> return 5 :: ([] Int)
[5]
> [5] >>= f
[6, 10]
> ([5] >>= f) >>= f
[7, 12, 11, 20]