Я хотел бы сделать свертку над n-арными структурами данных Tree. (fold - это также Aggregate в Linq). Мне удалось найти рабочее решение:
public static R Aggregate<T, R>(T node,
Func<T, IEnumerable<T>> getChildren,
Func<T, IEnumerable<R>, R> aggregator)
{
var childResults = getChildren(node)
.Select(c => Aggregate(c, getChildren, aggregator));
return aggregator(node, childResults);
}
getChildren
- функция, определяющая, как получить потомков данного узла. Он должен возвращать пустой IEnumerable для конечных узлов. aggregator
определяет, как обрабатывать узел, используя текущий узел и результаты его дочерних узлов.
Решение вроде работает, но есть некоторые проблемы:
Алгоритм является рекурсивным, он взорвет стек для глубоких деревьев.
Как я могу переписать функцию, чтобы предотвратить переполнение стека?Алгоритм ленивый, но не более чем.
например. еслиaggregator
использует только результатEnumerable.First
дочерних узлов, будет пройдена только самая левая ветвь дерева. Однако сEnumerable.Last
обход выполняется по всему дереву, даже если для вычислений требуется только самая правая ветвь.
Как я могу сделать алгоритм действительно ленивым?
Решения F # приветствуются, но предпочтительнее C #.