拆分IO和计算

时间:2012-02-28 22:22:26

标签: haskell

我想收到一个字符串,将其转换为列表并将列表的每个元素写入TChan。对于收到的每个字符串,我想分叉一个新进程。

我的问题是,当我尝试编译时,我得到与IO相关的错误:

Couldn't match expected type `IO ()' with actual type `[()]'

Couldn't match expected type `IO ()' with actual type `[IO ()]'

虽然我完全理解错误并知道它的起源(至少是第一个错误 - )但我现在已经不知道如何在我的示例中拆分IO计算并仍然实现我尝试做的事情。 / p>

write2TChan msg mtch = do
        let mymessages = words msg
        map (\x -> atomically $ writeTChan mtch x) mymessages
        return ()

main = withSocketsDo $ do
        s <- socket AF_INET Datagram defaultProtocol
        bindAddr <- inet_addr host
        bindSocket s (SockAddrInet port bindAddr)
        mtch <- newTChanIO
        let forever socket hosts = do
                (msg, host) <- receiveMessage socket
                return ()
                return (forkIO $ write2TChan msg mtch)
                --forkIO $ write2TChan msg mtch
                --tried w return () and above, same problem
                forever socket hosts
        forever s []
        sClose s

1 个答案:

答案 0 :(得分:6)

map的类型为map :: (a -> b) -> [a] -> [b],因此它始终返回列表。但是,do monad中IO块中的每个语句都必须为某些IO a添加a类型。

您希望相关函数mapM :: Monad m => (a -> m b) -> [a] -> m [b]在monad中执行相同的操作。由于您要忽略结果,我们可以使用变体mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

write2TChan msg mtch = do
    let mymessages = words msg
    mapM_ (\x -> atomically $ writeTChan mtch x) mymessages

对于您的其他功能,您应该可以直接使用forkIO。将其包含在return中完全没有任何意义,因为它会生成类型IO (IO a),即返回操作的操作。此外,当return ()不是do块中的最后一个语句时,let forever socket hosts = do (msg, host) <- receiveMessage socket forkIO $ write2TChan msg mtch forever socket hosts 是无操作,因此您不需要它。

这应该有效

hosts

但是,[]参数目前总是forever,所以除非你打算对此做些什么,否则你也可以摆脱它。另外,我会避免使用名称Control.Monad,因为{{1}}中已经有一个常用的具有该名称的函数。