module Main(main) where
import Text.Printf
data RxEvent a =
Value a
| Error String
| Done
deriving (Show,Eq)
notify :: (Monad m, Foldable t, Num a1) => t (RxEvent a -> t1) -> RxEvent a -> m a1
notify subs ev =
return $ Prelude.foldl (\ c s -> seq (s ev) (c+1) ) 0 subs
o name ev = do
putStrLn name
print ev
return 0
o1 = o "o1:"
o2 = o "o2:"
o3 = o "o3:"
main = do
nNotified <- notify [o1,o2,o3] (Value 42) :: IO Int
printf "%d subscribers notified\n" nNotified
return ()
看来,seq
在上面的代码段中失败了。 foldl
函数访问列表中的所有3个成员,但是函数o1 o2 o3
中没有输出。这次我做错了什么? :)
使用:main
在ghci中运行只生成“3个订阅者通知”,但没有来自它应该通知的函数的输出。
答案 0 :(得分:5)
seq
确保评估IO
个操作,但不执行。例如
print (seq (print 45) 12)
打印“12”,而不是“45 12”。对print 45
部分进行评估,以生成IO ()
值,但该值永远不会执行。
要运行IO操作,您必须直接或间接使用>>=
。
答案 1 :(得分:1)
我已经意识到目标函数的调用应该在monadic上下文中。所以,记住隐秘有意义的_
函数以及我偶然看到的M
结尾的函数,我尝试了像:t foldlM
和:t foldlM_
这样的ghci,但当然他们不在范围内,因为它们在Control.Monad
包内。我没有提到的包裹......
对我的问题的评论赞不绝口,我的代码片段的工作版本如下所示:
module Main(main) where
import Text.Printf
import Control.Monad
data RxEvent a =
Value a
| Error String
| Done
deriving (Show,Eq)
notify :: (Foldable t, Num b, Monad m) => t (RxEvent t1 -> m a) -> RxEvent t1 -> m b
notify subs ev = foldM (\ c s -> s ev >> return (c+1)) 0 subs
o name ev = do
putStrLn name
print ev
return 0
o1 = o "o1:"
o2 = o "o2:"
o3 = o "o3:"
main = do
nNotified <- notify [o1,o2,o3] (Value 42) :: IO Int
printf "%d subscribers notified\n" nNotified
return ()
获得的经验教训:对于那些试图以经验方式单独学习Haskell的人而不花费数小时来了解随机数量的软件包,可以预期会遇到这些非常简单的问题。
我仍然不太明白的是,为什么Control.Monad的内容是在一个额外的包中而不是Prelude的一部分,因为没有这些功能,就不可能有任何简单的事情......
这里,最后希望输出:
o1:
Value 42
o2:
Value 42
o3:
Value 42
3 subscribers notified