Zipper moves keep the represented tree, and replace changes only the focus full
This proof shows: correctness.
Setting. Trees are nil or nodes (l,x,r). A path is nil or c::p, where c is a crumb (left,x,s) or (right,x,s). Define
plug(t,nil)=t,plug(t,(left,x,s)::p)=plug((t,x,s),p),plug(t,(right,x,s)::p)=plug((s,x,t),p). A position in a tree T is a sequence of directions from the root. Define the position of a path by pos(nil)=⟨⟩ and pos(c::p)=pos(p)⋅⟨d⟩, where d is the direction of c. The zipper (t,p) represents the tree plug(t,p) with the position pos(p).
Lemma 1. For every path p and trees t,t′, the tree plug(t′,p) equals plug(t,p) with the subtree at pos(p) replaced by t′, and the subtree of plug(t,p) at pos(p) is t.
Proof. By induction on the length of p. For p=nil the position is the root, and both claims are clear. For p=(left,x,s)::p′, the tree plug(t,p) is plug((t,x,s),p′). By induction its subtree at pos(p′) is (t,x,s), so its subtree at pos(p′)⋅⟨left⟩=pos(p) is t. Also by induction, plug((t′,x,s),p′) is plug((t,x,s),p′) with the subtree at pos(p′) replaced by (t′,x,s), which is the same as replacing only the left child of that subtree, at pos(p), by t′. The right case is symmetric. □
Lemma 2 (moves). If (t,p) represents (T,π), then LEFT, RIGHT and UP, when they succeed, return zippers that represent T with the position π⋅⟨left⟩, π⋅⟨right⟩ and π without its last direction.
Proof. LEFT applies to t=(l,x,r) (lines L2 and L3) and returns (l,(left,x,r)::p) (line L4). By definition plug(l,(left,x,r)::p)=plug((l,x,r),p)=T, and the position is pos(p)⋅⟨left⟩. RIGHT is the same with (right,x,l) and plug(r,(right,x,l)::p)=plug((l,x,r),p) (lines L5 and L6). UP applies to p=(d,x,s)::p′ (lines L7 and L8). If d=left it returns ((t,x,s),p′) (line L9), and plug((t,x,s),p′)=plug(t,p)=T; if d=right it returns ((s,x,t),p′) (line L10), and the same holds. The position is pos(p′), which is π without its last direction. □
Lemma 3 (replace and top). If (t,p) represents (T,π), then REPLACE((t,p),t′) represents T with the subtree at π replaced by t′, at the same position. TOP returns a zipper with an empty path whose focus is T.
Proof. Line L11 returns (t′,p), and Lemma 1 gives the first claim. TOP applies UP while the path is not nil (line L12). Each UP shortens the path by one and keeps the tree by Lemma 2, so the loop ends after ∣p∣ steps with (t′′,nil), and t′′=plug(t′′,nil)=T. □
Theorem. Every sequence of operations from from_tree(T_0) gives zippers whose represented trees and positions are those of the abstract type, to_tree returns the represented tree, and no operation changes what an existing zipper represents.
Proof. from_tree(T_0) returns (T0,nil), which represents T0 at the root. By Lemmas 2 and 3 each operation maps a zipper for (T,π) to a zipper for the correct result, so by induction on the number of operations every zipper is correct, and to_tree returns the focus of TOP, which is the represented tree. No line writes to an existing node, crumb or path; each builds new cells that point to old ones. The meaning plug(t,p) of a zipper depends only on the cells reachable from it, which never change, so every earlier zipper keeps its meaning. ■