Насколько я понимаю, функция «выполняет» каждый элемент в списке, который должен быть «действием» (монадой ввода-вывода).
Это верно для IO, но в вашем примере кода вы не используете монаду IO, вы используете монаду списка (функция, которую вы предоставляете mapM, возвращает список ([x]
), а не IO).
mapM
определяется как mapM f as = sequence (map f as)
. Если f возвращает IO, это означает, что для каждого элемента в списке он создает IO, применяя f к элементу. Затем он превращает список IO, которые карта возвращает, в IO, «содержащий» список с использованием последовательности (поэтому, когда вы выполняете IO, вы получаете список, содержащий значения не-IO).
Для списков это означает, что он создает список списков, применяя f
к каждому элементу as
. Затем он использует sequence
для создания списка списков, который содержит все возможные способы занести один элемент каждого списка в списки списков (например, sequence [[1,2],[3,4]]
возвращает [[1,3],[1,4],[2,3],[2,4]]
).