Учитывая следующее простое определение BST:Монады и пользовательские функции обхода в Haskell
data Tree x = Empty | Leaf x | Node x (Tree x) (Tree x)
deriving (Show, Eq)
inOrder :: Tree x -> [x]
inOrder Empty = []
inOrder (Leaf x) = [x]
inOrder (Node root left right) = inOrder left ++ [root] ++ inOrder right
Я хотел бы написать функцию в заказ, который может иметь побочные эффекты. Я добился того, что с:
inOrderM :: (Show x, Monad m) => (x -> m a) -> Tree x -> m()
inOrderM f (Empty) = return()
inOrderM f (Leaf y) = f y >> return()
inOrderM f (Node root left right) = inOrderM f left >> f root >> inOrderM f right
-- print tree in order to stdout
inOrderM print tree
Это прекрасно работает, но это, кажется, повторяющаяся - та же логика уже присутствует в заказовМои и мой опыт работы с Haskell заставляет меня верить, что я, вероятно, делать что-то неправильно, если я Я пишу аналогичную вещь дважды.
Есть ли способ, которым я могу написать одну функцию inOrder, которая может принимать либо чистые, либо монадические функции?
Это может быть полезно понимать, что mapM_ е просто сокращение для sequence_. map f - То есть вы * можете * применить функцию (a -> m b) к каждому из ваших элементов inOrder с помощью простой карты ol. Теперь у вас есть список монадических действий, но у них нет порядка. Последовательность функций_ затем берет их и по существу применяет к ним последовательно, что дает монадическое действие, которое делает их в порядке списка. Разумеется, магия оптимизации означает, что этот список может очень хорошо никогда не строиться или быть в памяти сразу! – MtnViewMark
mapM аналогичен, но использует последовательность, и последовательность такая же, как и последовательность_, только она собирает результаты при выполнении монадических действий и делает эту коллекцию результатом составного действия. – MtnViewMark