039 — Convert a Tree to a Dotstring Representation
Tutorial Video
Text description (accessibility)
This video demonstrates the "039 — Convert a Tree to a Dotstring Representation" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. The dotstring representation of a binary tree (OCaml 99 Problems #39) uses a preorder traversal where leaves are represented by `.` characters. Key difference from OCaml: 1. **Cursor style**: Rust uses `&mut usize` position cursor (mutable reference). OCaml returns `(result, new_position)` pairs — the state
Tutorial
The Problem
The dotstring representation of a binary tree (OCaml 99 Problems #39) uses a preorder traversal where leaves are represented by . characters. A node x with left subtree l and right subtree r becomes x followed by the dotstring of l then r. The self-delimiting property — you can parse the string left to right without needing parentheses — makes it efficient for both storage and streaming.
Dotstrings are used in compact tree serialization, hash computation of trees (trees with the same structure and values have the same dotstring hash), and in algorithms that transmit tree structure over byte channels. The format is equivalent to a Huffman-encoded tree stored as a bitstring prefix code.
🎯 Learning Outcomes
. for absent children — no delimiters needed between childrenCode Example
#![allow(clippy::all)]
// Placeholder — pending conversionKey Differences
&mut usize position cursor (mutable reference). OCaml returns (result, new_position) pairs — the state-threading style that avoids mutation.. consumes 1 character; a node character c consumes 1 + |left_dotstring| + |right_dotstring| characters, and both subtrees are self-delimiting by induction.^ inside recursion is O(n²) total; use Buffer for O(n)."x.y.z.." where each character is a node value and . represents a leaf. The format encodes the pre-order traversal, with leaves as dots.String; the parser (example 040) consumes it as a Chars iterator. Threading the iterator through recursive calls is the key parsing pattern.OCaml Approach
OCaml's version: let rec to_dotstring = function | Leaf -> "." | Node (c, l, r) -> String.make 1 c ^ to_dotstring l ^ to_dotstring r. Reconstruction: let rec from_dotstring pos s = if s.[pos] = '.' then (Leaf, pos + 1) else let c = s.[pos] in let (l, p1) = from_dotstring (pos + 1) s in let (r, p2) = from_dotstring p1 s in (Node (c, l, r), p2). Returns (tree, next_position) pairs.
Full Source
#![allow(clippy::all)]
// Placeholder — pending conversionDeep Comparison
OCaml vs Rust: Dotstring Tree
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
tree_hash(tree: &Tree<char>) -> u64 that computes a deterministic hash of the tree by hashing its dotstring. Two structurally equal trees must produce the same hash.DotStringDecoder as an iterator that accepts one character at a time and emits Node or Leaf events as they are recognized. This enables streaming tree processing.0 for Leaf, 1 followed by left/right for Node. Count bits needed vs character bytes.| to separate the label from children). Implement both serialization and parsing.