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