signature SEQUENCE =
sig
type 'a seq
val map : ('a -> 'b) -> 'a seq -> 'b seq
val reduce : (('a * 'a) -> 'a) -> 'a -> 'a seq -> 'a
val tabulate : (int -> 'a) -> int -> 'a seq
val nth : int -> 'a seq -> 'a
end
structure TreeSeq : SEQUENCE =
struct
datatype 'a tree = Leaf of 'a | Empty | Node of 'a tree * 'a tree
type 'a seq = 'a tree
fun map f t = case t of
Leaf x => Leaf (f x)
| Empty => Empty
| Node (t1 , t2) => Node (map f t1, map f t2)
fun reduce n e t =
case t of
Leaf x => x
| Empty => e
| Node (t1 , t2) => n (reduce n e t1, reduce n e t2)
(* helper function is not visible to clients *)
fun numLeaves t =
case t of
Empty => 0
| Leaf _ => 1
| Node (t1,t2) => numLeaves t1 + numLeaves t2
fun nth i s =
case (s , i) of
(Empty , _) => raise Fail "out of range"
| (Leaf x , 0) => x
| (Leaf x , _) => raise Fail "out of range"
| (Node (t1 , t2) , n) =>
let val s1 = numLeaves t1
in
case n < s1 of
true => nth n t1
| false => nth (n - s1) t2
end
fun tabulate f n =
let
(* return the sequence *)
fun tabulate' (from, to) =
case to - from of
0 => Empty
| 1 => Leaf (f from)
| diff => Node (tabulate' (from , from + diff div 2) , tabulate' (from + diff div 2 , to))
in
tabulate' (0 , n)
end
end
(* optimized *)
structure TreeSeq : SEQUENCE =
struct
(* representation invariant:
in Node (t1 , s1 , t2) , s1 is the number of leaves in t1
*)
datatype 'a tree = Leaf of 'a | Empty | Node of 'a tree * int * 'a tree
type 'a seq = 'a tree
fun map f t = case t of
Leaf x => Leaf (f x)
| Empty => Empty
| Node (t1 , s1 , t2) => Node (map f t1, s1, map f t2)
(* don't show *)
fun reduce n e t =
case t of
Leaf x => x
| Empty => e
| Node (t1 , _ , t2) => n (reduce n e t1, reduce n e t2)
fun nth i s =
case (s , i) of
(Empty , _) => raise Fail "out of range"
| (Leaf x , 0) => x
| (Leaf x , _) => raise Fail "out of range"
| (Node (t1 , s1 , t2) , n) =>
case n < s1 of
true => nth n t1
| false => nth (n - s1) t2
(* make a mistake! *)
fun tabulate f n =
let
(* return the sequence *)
fun tabulate' (from, to) =
case to - from of
0 => Empty
| 1 => Leaf (f from)
| diff => Node (tabulate' (from , from + diff div 2) ,
diff div 2, (* + 1 BUG *)
tabulate' (from + diff div 2 , to))
in
tabulate' (0 , n)
end
end