Compte tenu de la définition simple de BST suivante:Monades et fonctions traversal personnalisés dans 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
Je voudrais écrire une fonction dans l'ordre qui peuvent avoir des effets secondaires. J'ai réalisé que, avec:
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
Cela fonctionne bien, mais il semble répétitif - la même logique est déjà présent dans afinde et mon expérience avec Haskell me porte à croire que je fais sans doute quelque chose de mal si je J'écris une chose similaire deux fois.
Y a-t-il un moyen pour que je puisse écrire une seule fonction dans InOrder qui peut prendre des fonctions pures ou monadiques?
Il pourrait être intéressant de se rendre compte que mapM_ f est juste un raccourci pour sequence_. map f - Autrement dit, vous pouvez * appliquer * une fonction (a -> m b) à chacun de vos éléments inOrder avec une simple carte. Maintenant vous avez une liste d'actions monadiques, mais elles n'ont aucun ordre. La fonction sequence_ les prend alors, et leur applique essentiellement >> en séquence, ce qui donne une action monadique qui les fait dans l'ordre de la liste. Bien sûr, la magie de l'optimisation signifie que cette liste peut très bien ne jamais être construite ou être en mémoire en même temps! – MtnViewMark
mapM est similaire mais utilise une séquence, et la séquence est la même que sequence_ only elle recueille les résultats lorsqu'elle exécute les actions monadiques et fait de cette collection le résultat de l'action composée. – MtnViewMark