X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=tree_and_list_zippers.mdwn;h=fafde0a4d8feaf032b3468f08e9e677cdf5e068f;hp=5d26ca97124bd726bbf6c715404f00f02368aee7;hb=49e6889d3ceb77526298a84549df44871caaf7a0;hpb=8e50e0b21cef6e6d5aba8265bf2aa0adbf6647d2 diff --git a/tree_and_list_zippers.mdwn b/tree_and_list_zippers.mdwn index 5d26ca97..fafde0a4 100644 --- a/tree_and_list_zippers.mdwn +++ b/tree_and_list_zippers.mdwn @@ -5,28 +5,28 @@ Say you've got some moderately-complex function for searching through a list, for example: let find_nth (test : 'a -> bool) (n : int) (lst : 'a list) : (int * 'a) -> - let rec helper (position : int) n lst = - match lst with - | [] -> failwith "not found" - | x :: xs when test x -> (if n = 1 - then (position, x) - else helper (position + 1) (n - 1) xs - ) - | x :: xs -> helper (position + 1) n xs - in helper 0 n lst;; + let rec helper (position : int) n lst = + match lst with + | [] -> failwith "not found" + | x :: xs when test x -> (if n = 1 + then (position, x) + else helper (position + 1) (n - 1) xs + ) + | x :: xs -> helper (position + 1) n xs + in helper 0 n lst;; This searches for the `n`th element of a list that satisfies the predicate `test`, and returns a pair containing the position of that element, and the element itself. Good. But now what if you wanted to retrieve a different kind of information, such as the `n`th element matching `test`, together with its preceding and succeeding elements? In a real situation, you'd want to develop some good strategy for reporting when the target element doesn't have a predecessor and successor; but we'll just simplify here and report them as having some default value: let find_nth' (test : 'a -> bool) (n : int) (lst : 'a list) (default : 'a) : ('a * 'a * 'a) -> - let rec helper (predecessor : 'a) n lst = - match lst with - | [] -> failwith "not found" - | x :: xs when test x -> (if n = 1 - then (predecessor, x, match xs with [] -> default | y::ys -> y) - else helper x (n - 1) xs - ) - | x :: xs -> helper x n xs - in helper default n lst;; + let rec helper (predecessor : 'a) n lst = + match lst with + | [] -> failwith "not found" + | x :: xs when test x -> (if n = 1 + then (predecessor, x, match xs with [] -> default | y::ys -> y) + else helper x (n - 1) xs + ) + | x :: xs -> helper x n xs + in helper default n lst;; This duplicates a lot of the structure of `find_nth`; it just has enough different code to retrieve different information when the matching element is found. But now what if you wanted to retrieve yet a different kind of information...? @@ -66,7 +66,7 @@ The kind of data structure we're looking for here is called a **list zipper**. T would be represented as `([30; 20; 10], [40; 50; 60; 70; 80; 90])`. To move forward in the base list, we pop the head element `40` off of the head element of the second list in the zipper, and push it onto the first list, getting `([40; 30; 20; 10], [50; 60; 70; 80; 90])`. To move backwards again, we pop off of the first list, and push it onto the second. To reconstruct the base list, we just "move backwards" until the first list is empty. (This is supposed to evoke the image of zipping up a zipper; hence the data structure's name.) -We had some discussio in seminar of the right way to understand the "zipper" metaphor. I think it's best to think of the tab of the zipper being here: +We had some discussion in seminar of the right way to understand the "zipper" metaphor. I think it's best to think of the tab of the zipper being here: t a