我想接收一个字符串,将其转换为列表并将列表的每个元素写入TChan.对于收到的每个字符串,我想分叉一个新进程.
我的问题是,当我尝试编译时,我得到与IO相关的错误:
Couldn't match expected type `IO ()' with actual type `[()]'
Run Code Online (Sandbox Code Playgroud)
要么
Couldn't match expected type `IO ()' with actual type `[IO ()]'
Run Code Online (Sandbox Code Playgroud)
虽然我完全理解错误并知道它的起源(至少是第一个错误 - )但我现在已经没有想法如何在我的示例中拆分IO计算并仍然实现我尝试做的事情.
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
Run Code Online (Sandbox Code Playgroud)
map有类型map :: (a -> b) -> [a] -> [b],所以它总是返回一个列表.但是,monad中do块中的每个语句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
Run Code Online (Sandbox Code Playgroud)
对于您的其他功能,您应该可以forkIO直接使用.包装它return根本没有任何意义,因为它会产生类型IO (IO a),即一个动作返回一个动作.另外,return ()当它不是do块中的最后一个语句时,是一个无操作,所以你不需要它.
这应该工作
let forever socket hosts = do
(msg, host) <- receiveMessage socket
forkIO $ write2TChan msg mtch
forever socket hosts
Run Code Online (Sandbox Code Playgroud)
但是,这个hosts论点目前总是[]如此,所以除非你打算对此做些什么,否则你也可以摆脱它.此外,我会避免使用该名称,forever因为该名称已经有一个常用的功能Control.Monad.