Skip to main content

pattern_core/pattern/
unfold.rs

1//! unfold: anamorphism for building a Pattern tree from a seed.
2//!
3//! Ported from `Pattern.Core.unfold` in the Haskell reference implementation.
4//! Implemented iteratively with an explicit work stack to avoid stack overflow
5//! on deep hierarchies.
6
7use crate::pattern::Pattern;
8
9/// Anamorphism: expand a seed into a `Pattern<V>` tree.
10///
11/// `expand` receives a seed and returns the value for the current node plus
12/// a list of child seeds. The tree is built iteratively (work stack) to avoid
13/// stack overflow for arbitrarily deep hierarchies.
14///
15/// # Examples
16///
17/// ```rust
18/// use pattern_core::unfold;
19///
20/// // Build a depth-3 binary tree from a depth seed
21/// let tree = unfold(|depth: u32| {
22///     if depth == 0 {
23///         (depth, vec![])
24///     } else {
25///         (depth, vec![depth - 1, depth - 1])
26///     }
27/// }, 2u32);
28///
29/// assert_eq!(tree.value, 2);
30/// assert_eq!(tree.elements.len(), 2);
31/// assert_eq!(tree.elements[0].value, 1);
32/// ```
33pub fn unfold<A, V>(expand: impl Fn(A) -> (V, Vec<A>), seed: A) -> Pattern<V> {
34    // Two-phase iterative implementation using an explicit work stack.
35    // Work::Expand(seed)       — expand the seed, push children then Collect
36    // Work::Collect(value, n)  — pop n children from result stack, assemble Pattern
37
38    enum Work<A, V> {
39        Expand(A),
40        Collect(V, usize),
41    }
42
43    let mut work_stack: Vec<Work<A, V>> = vec![Work::Expand(seed)];
44    let mut result_stack: Vec<Pattern<V>> = Vec::new();
45
46    while let Some(item) = work_stack.pop() {
47        match item {
48            Work::Expand(s) => {
49                let (value, children) = expand(s);
50                let n = children.len();
51                // Collect marker runs after all children are assembled
52                work_stack.push(Work::Collect(value, n));
53                // Push children in reverse so leftmost is processed first (LIFO)
54                for child in children.into_iter().rev() {
55                    work_stack.push(Work::Expand(child));
56                }
57            }
58            Work::Collect(value, n) => {
59                let start = result_stack.len() - n;
60                let elements: Vec<Pattern<V>> = result_stack.drain(start..).collect();
61                result_stack.push(Pattern { value, elements });
62            }
63        }
64    }
65
66    result_stack
67        .pop()
68        .expect("unfold: result stack should have exactly one element")
69}