Вы смотрели на Криса Окасаки "Нумерация в ширину: уроки из небольшого упражнения по разработке алгоритма" ? Модуль Data.Tree
включает в себя конструктор монадических деревьев с именем unfoldTreeM_BF
, который использует алгоритм, адаптированный из этого документа.
Вот пример, который, я думаю, соответствует тому, что вы делаете:
Предположим, я хочу найти бесконечное двоичное дерево строк, где все левые дочерние элементы являются родительской строкой плюс "a", а правые дочерние элементы являются родительским элементом плюс "bb". Я мог бы использовать unfoldTreeM_BF
для поиска дерева в ширину и вернуть найденное дерево до решения:
import Control.Monad.State
import Data.Tree
children :: String -> [String]
children x = [x ++ "a", x ++ "bb"]
expand query x = do
found <- get
if found
then return (x, [])
else do
let (before, after) = break (==query) $ children x
if null after
then return (x, before)
else do
put True
return (x, before ++ [head after])
searchBF query = (evalState $ unfoldTreeM_BF (expand query) []) False
printSearchBF = drawTree . searchBF
Это не очень красиво, но работает. Если я ищу «aabb», я получаю именно то, что хочу:
|
+- a
| |
| +- aa
| | |
| | +- aaa
| | |
| | `- aabb
| |
| `- abb
|
`- bb
|
+- bba
|
`- bbbb
Если это то, что вы описываете, вам не составит труда адаптироваться к вашему типу дерева.
ОБНОВЛЕНИЕ: Вот бесплатная версия expand
, на случай, если вам нравятся такие вещи:
expand q x = liftM ((,) x) $ get >>= expandChildren
where
checkChildren (before, []) = return before
checkChildren (before, t:_) = put True >> return (before ++ [t])
expandChildren True = return []
expandChildren _ = checkChildren $ break (==q) $ children x
(Спасибо camccann за то, что он оттолкнул меня от старых привычек структуры управления. Надеюсь, эта версия более приемлема.)