Они на самом деле не связаны.Я постараюсь объяснить, что делает каждый из них.Я предполагаю, что у вас есть общее представление о том, что такое монада.
liftM :: Monad m => (a -> b) -> (m a -> m b)
позволяет вам использовать обычную функцию в монаде.Она берет функцию a -> b
и превращает ее в функцию m a -> m b
, которая делает то же самое, что и исходная функция, но делает это в монаде.Результирующая функция ничего не «делает» с монадой (не может, потому что исходная функция не знала, что она находится в монаде).Например:
main :: IO ()
main = do
output <- liftM ("Hello, " ++) getLine
putStrLn output
Функция ("Hello, " ++) :: String -> String
добавляет «Hello» к строке.Передача в liftM
создает функцию типа IO String -> IO String
- теперь у вас есть функция, которая работает в монаде IO.Он не выполняет ввода-вывода, но может принимать действие ввода-вывода в качестве входных данных и создает действие ввода-вывода в качестве выходных данных.Следовательно, я могу передать getLine
в качестве входных данных, и он вызовет getLine
, добавит «Hello» в начало результата и вернет его как действие ввода-вывода.
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
вполнеразные;обратите внимание, что в отличие от liftM
, он принимает монадическую функцию.Например, в монаде IO он имеет тип (a -> IO b) -> [a] -> IO [b]
.Она очень похожа на обычную функцию map
, только она применяет монадическое действие к списку и создает список результатов, заключенный в монадическое действие.Например (довольно плохо):
main2 :: IO ()
main2 = do
output <- mapM (putStrLn . show) [1, 2, 3]
putStrLn (show output)
Это печатает:
1
2
3
[(),(),()]
То, что он делает, выполняет итерацию по списку, применяя (putStrLn . show)
к каждому элементу в списке(с эффектом ввода-вывода распечатывания каждого из чисел), а также преобразование чисел в значение ()
.Результирующий список состоит из [(), (), ()]
- вывод putStrLn
.