2012-02-28 2 views
1

Я хочу получить строку, преобразовать ее в список и написать каждый элемент списка в TChan. Для каждой полученной строки я хочу разблокировать новый процесс.split IO и вычисление

Моя проблема заключается в том, что я получаю ошибки, связанные с IO, когда я пытаюсь скомпилировать это:

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

или

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

Хотя я полностью понимаю ошибку и знать, где оно происходит от (- по крайней мере, первая ошибка). Теперь я не понимаю, как я мог бы разбить 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 

ответ

6

map имеет тип map :: (a -> b) -> [a] -> [b], поэтому он всегда возвращает список. Однако каждый оператор в блоке do в монаде IO должен иметь тип IO a для некоторого a.

Требуется связанная функция mapM :: Monad m => (a -> m b) -> [a] -> m [b], которая делает то же самое в монаде. Поскольку вы хотите проигнорировать результат, мы можем использовать вариант 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() является no-op, если это не последний оператор в блоке do, поэтому вам это не нужно.

Это должно работать

let forever socket hosts = do 
     (msg, host) <- receiveMessage socket 
     forkIO $ write2TChan msg mtch 
     forever socket hosts 

хотя, hosts аргумент в настоящее время всегда [], поэтому если вы не собираетесь делать что-то о том, что вы можете избавиться от этого тоже. Кроме того, я бы избегал имени forever, так как в Control.Monad с этим именем уже используется обычная функция.

+0

Немного не по теме: будет ли иметь большое значение использование парного комбинатора вместо forkIO? Я обеспокоен тем, что в моем примере количество потоков не ограничено, конечно. –

+0

@JFritsch: 'par' предназначен для параллелизма в чистом коде. Здесь вы делаете параллелизм с множеством побочных эффектов, а не с параллелизмом, поэтому 'par' даже не вариант для начала. Кроме того, помните, что 'forkIO' порождает легкие потоки Haskell, поэтому, если вы не размножаете тысячи из них, я бы не стал слишком беспокоиться об этом. – hammar