Сложность этой проблемы заключается в том, что существует несколько структур (путь - list
, каждый узел - list
и поддерево), которые необходимо пройти рекурсивно в одно и то же время, чтобы он работал,Делать это в одной функции становится очень трудно.
Вот почему мне нравится упрощать проблему, разбивая ее на более мелкие части.Здесь мы собираемся использовать 2 взаимно рекурсивных функции (обратите внимание на синтаксис).Сначала я собираюсь переименовать функции, чтобы лучше понять, что они делают.Я также избегаю повторять одно и то же имя для функций и переменных, поскольку это сбивает с толку.Моя первая функция будет иметь дело только с обходом пути p
:
let rec addPath (p : string list) (Node ns) =
match p with
| [] -> Node ns
| hp :: tp -> Node (addHeadPath hp tp ns)
Я использую сопоставление с шаблоном по второму параметру (Node ns)
, чтобы получить список подузлов, потому что следующая функция будет проходить через этоlist.
В моем выражении match
я хотел бы позаботиться сначала о пустом регистре, который является концом рекурсии.Второй случай отделяет голову и хвост и отправляет их в другую функцию для обработки:
and addHeadPath hp tp ns =
match ns with
| [] -> [hp, addPath tp (Node[]) ]
| (nn, st) :: tn when nn = hp -> (nn, addPath tp st ) :: tn
| hn :: tn -> hn :: addHeadPath hp tp tn
addHeadPathTo
является взаимно рекурсивным с addPathTo
, поэтому я связываю их вместе с and
вместо другогоlet rec
.
Опять же сначала рассматривается пустой случай, который возвращает список с одним узлом и вызывает addPathTo
, чтобы добавить оставшуюся часть пути.Второй случай, когда узел уже существует, и в этом случае мы добавляем остаток пути к поддереву st
.Третий случай продолжает просматривать список узлов, вызывая себя рекурсивно.
Вы вызываете его следующим образом:
createEmptyFsTree()
|> addPath ["MainNode";"nodeA";"nodeB"]
|> addPath ["MainNode";"nodeC";"nodeD"]
|> addPath ["MainNode";"nodeC";"nodeE"]
|> printfn "%A"