我正在“为哈萨克学到一个好东西”一书中学习filterM
功能。由Miran Lipovaca撰写。对于以下示例:
keepSmall :: Int -> Writer [String] Bool
keepSmall x
| x < 4 = do
tell ["Keeping " ++ show x]
return True
| otherwise = do
tell [show x ++ " is too large, throwing it away"]
return False
通过将此功能与
filterM
一起使用所获得的结果如下:> runWriter $ filterM keepSmall [9,1,5,2,10,3]
([1,2,3],["9 is too large, throwing it away","Keeping 1","5 is too large,
throwing it away","Keeping 2","10 is too large, throwing it away","Keeping 3"])
关于
filterM
结果的类型,我知道filterM
具有以下类型声明:filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
由于本示例中使用的monad是
Writer [String]
,由filterM
生成的列表的类型是否为Writer [String] [Int]
?如果是这种情况,这是为什么结果类型为([Int], [String])
的原因,因为Writer w a
等同于元组(a,w)
? 最佳答案
那是因为runWriter
的类型
runWriter :: Writer w a -> (a, w)
从Hoogle来看,它实际上只是将编写器计算作为(结果,输出)对展开。这就是为什么您成对获得结果的原因。
一个小例子,看看它在其他情况下如何工作:
runWriter (tell $ return "Hello" ())
=> ((),"Hello")