use pattern_core::Pattern;
fn main() {
println!("=== Comonad Operations Example ===\n");
basic_extract_extend();
helper_functions();
pattern_inspector();
custom_computation();
composition_example();
}
fn basic_extract_extend() {
println!("--- Example 1: Basic Extract and Extend ---");
let p = Pattern::pattern(
"root",
vec![
Pattern::pattern("a", vec![Pattern::point("x")]),
Pattern::point("b"),
],
);
println!("Root value: {}", p.extract());
let depths = p.extend(&|subp: &Pattern<&str>| subp.depth());
println!("Root depth: {}", depths.extract());
println!("Child 'a' depth: {}", depths.elements()[0].extract());
println!("Child 'b' depth: {}", depths.elements()[1].extract());
println!(
"Nested child 'x' depth: {}\n",
depths.elements()[0].elements()[0].extract()
);
}
fn helper_functions() {
println!("--- Example 2: Helper Functions ---");
let p = Pattern::pattern(
"root",
vec![
Pattern::pattern("a", vec![Pattern::point("x"), Pattern::point("y")]),
Pattern::pattern("b", vec![Pattern::point("z")]),
Pattern::point("c"),
],
);
let depths = p.depth_at();
println!("Depths:");
println!(" root: {}", depths.extract());
println!(" a: {}", depths.elements()[0].extract());
println!(" b: {}", depths.elements()[1].extract());
println!(" c: {}", depths.elements()[2].extract());
let sizes = p.size_at();
println!("\nSizes (node counts):");
println!(" root: {}", sizes.extract());
println!(" a subtree: {}", sizes.elements()[0].extract());
println!(" b subtree: {}", sizes.elements()[1].extract());
println!(" c: {}", sizes.elements()[2].extract());
let paths = p.indices_at();
println!("\nPaths from root:");
println!(" root: {:?}", paths.extract());
println!(" a: {:?}", paths.elements()[0].extract());
println!(
" a's first child: {:?}",
paths.elements()[0].elements()[0].extract()
);
println!(" b: {:?}", paths.elements()[1].extract());
println!(" c: {:?}\n", paths.elements()[2].extract());
}
fn pattern_inspector() {
println!("--- Example 3: Pattern Inspector ---");
let p = Pattern::pattern(
"document",
vec![
Pattern::pattern(
"section1",
vec![
Pattern::pattern("paragraph1", vec![Pattern::point("text1")]),
Pattern::point("paragraph2"),
],
),
Pattern::pattern(
"section2",
vec![
Pattern::point("paragraph3"),
Pattern::pattern(
"subsection",
vec![Pattern::point("paragraph4"), Pattern::point("paragraph5")],
),
],
),
Pattern::point("footer"),
],
);
let depths = p.depth_at();
let sizes = p.size_at();
let paths = p.indices_at();
let max_depth = depths.fold(0, |max, &d| max.max(d));
println!("Maximum nesting depth: {}", max_depth);
let total_nodes = p.size();
println!("Total nodes: {}", total_nodes);
let threshold = (total_nodes as f64 * 0.3) as usize;
println!("\nHeavy subtrees (> 30% of total = {}+):", threshold);
find_heavy_subtrees(&sizes, &paths, threshold, &[]);
println!();
}
fn find_heavy_subtrees(
sizes: &Pattern<usize>,
paths: &Pattern<Vec<usize>>,
threshold: usize,
current_path: &[usize],
) {
if *sizes.extract() > threshold {
println!(" Path {:?}: {} nodes", paths.extract(), sizes.extract());
}
for (i, (size_child, path_child)) in sizes
.elements()
.iter()
.zip(paths.elements().iter())
.enumerate()
{
let mut new_path = current_path.to_vec();
new_path.push(i);
find_heavy_subtrees(size_child, path_child, threshold, &new_path);
}
}
fn custom_computation() {
println!("--- Example 4: Custom Context-Aware Computation ---");
let p = Pattern::pattern(
"root",
vec![
Pattern::point("a"),
Pattern::point("b"),
Pattern::point("c"),
],
);
let balances = p.extend(&|subp: &Pattern<&str>| {
if subp.elements().is_empty() {
1.0 } else {
let sizes: Vec<usize> = subp.elements().iter().map(|e| e.size()).collect();
let avg = sizes.iter().sum::<usize>() as f64 / sizes.len() as f64;
let variance =
sizes.iter().map(|&s| (s as f64 - avg).powi(2)).sum::<f64>() / sizes.len() as f64;
1.0 / (1.0 + variance) }
});
println!("Balance factors (1.0 = perfectly balanced):");
println!(" root: {:.3}", balances.extract());
println!();
}
fn composition_example() {
println!("--- Example 5: Composition with Existing Operations ---");
let p = Pattern::pattern(
"root",
vec![
Pattern::pattern("a", vec![Pattern::point("x")]),
Pattern::pattern(
"b",
vec![
Pattern::pattern("y", vec![Pattern::point("z")]),
Pattern::point("w"),
],
),
Pattern::point("c"),
],
);
let total_depth: usize = p.depth_at().fold(0, |acc, &d| acc + d);
println!("Sum of all depths: {}", total_depth);
let deep_positions = p.depth_at();
let positions_with_depth_gt_1 = count_positions_with_depth(&deep_positions, 1);
println!(
"Number of positions with depth > 1: {}",
positions_with_depth_gt_1
);
let depth_labels = p.depth_at().map(|d| format!("depth={}", d));
println!("\nDepth labels:\n root: {}", depth_labels.extract());
println!(" first child: {}", depth_labels.elements()[0].extract());
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct Metrics {
depth: usize,
size: usize,
balance: f64,
}
let metrics = p.extend(&|subp: &Pattern<&str>| {
let sizes: Vec<usize> = subp.elements().iter().map(|e| e.size()).collect();
let balance = if sizes.is_empty() {
1.0
} else {
let avg = sizes.iter().sum::<usize>() as f64 / sizes.len() as f64;
let variance =
sizes.iter().map(|&s| (s as f64 - avg).powi(2)).sum::<f64>() / sizes.len() as f64;
1.0 / (1.0 + variance)
};
Metrics {
depth: subp.depth(),
size: subp.size(),
balance,
}
});
println!("\nCombined metrics at root:\n {:?}\n", metrics.extract());
}
fn count_positions_with_depth(depths: &Pattern<usize>, threshold: usize) -> usize {
let mut count = 0;
if *depths.extract() > threshold {
count += 1;
}
for child in depths.elements() {
count += count_positions_with_depth(child, threshold);
}
count
}