Как я могу использовать карту над списком с помощью нотации do - т.е. избегать типа `IO ()'с типом`[IO ()]'?

Так что этот вопрос касается Монад в более общем плане (в частности, для Фэй), но в моем примере используется монада IO.

У меня есть функция, в которой вход представляет собой список строк, и я хотел бы напечатать каждую строку по одной. Итак, вот моя идея:

funct :: [String] -> ?
funct strs = do
    map putStrLn strs

Но не работает, потому что возвращает тип [IO ()]. Поэтому мой вопрос заключается в том, как бы я отобразил список и обработал его, как если бы я выполнял функцию построчно, в типичном стиле нотации, итеративном стиле (как показано ниже)?

funct :: [String] -> IO ()
funct strs = do
    putStrLn (strs !! 0)
    putStrLn (strs !! 1)
    ...

2 ответа

Решение

Большинство стандартных функций списка библиотек имеют монадические версии, которые заканчиваются на M:

map :: (a -> b) -> [a] -> [b]
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]

replicate :: Int -> a -> [a]
replicateM :: (Monad m) => Int -> m a -> m [a]

и т. д. Иногда они находятся в Preludeиногда они находятся в Control.Monad, Я рекомендую использовать Google, чтобы найти их.

Специально для вашего случая я использую mapM_ putStrLn довольно часто.

Используйте последовательность

sequence $ map putStrLn strings

последовательность вытаскивает монаду из списка монад

sequence :: Monad m => [m a] -> m [a]

таким образом преобразуя (отобразите строки stStrLn)::[IO a] в IO [a]. Возможно, вы захотите использовать связанную sequence_, чтобы также сбросить возвращаемое значение.

Вы также можете использовать forM_:: Monad m => [a] -> (a -> m b) -> m () (который часто выглядит лучше, но мне кажется, что это необходимо).

Другие вопросы по тегам