I created a simple sorted binary tree(see below) and I decided to display(iter) the contents of the tree in order of smallest to largest.
module MyBtree =
struct
type 'a btree = Empty | Btree of ('a * 'a btree * 'a btree)
let empty = Empty
let rec display toString bt =
match bt with
| Empty -> print_endline "Empty"
| Btree (d, left, right) ->
print_endline (toString d);
display toString left;
display toString right
let rec add data bt =
match bt with
| Empty -> Btree (data, Empty, Empty)
| Btree (d, left, right) ->
if (data < d)
then
Btree (d, add data left, right)
else if (data > d)
then
Btree (d, left, add data right)
else
bt
type 'a btreeList = Data of 'a | Node of 'a btree
let buildLeftList bt =
let rec buildLeftListAux bt acc =
match bt with
| Empty -> acc
| Btree (d, left, right) ->
buildLeftListAux left ((Data d)::(Node right)::acc) in
buildLeftListAux bt []
let buildList bL =
let rec buildListAux bL acc =
match bL with
| [] -> List.rev acc
| hd::tl ->
(
match hd with
| Data d -> buildListAux tl (d::acc)
| Node bt -> buildListAux ((buildLeftList bt) @ tl) acc
) in
buildListAux bL []
let iter func bt = List.iter func (buildList (buildLeftList bt))
end
let b =
List.fold_left
(fun acc elem -> MyBtree.add elem acc)
MyBtree.empty
[10; 1; 9; 2; 8; 3; 7; 4; 6; 5;]
let () =
b
|> MyBtree.display string_of_int
let () = print_endline "\n\n"
let () =
b
|> MyBtree.iter (fun x -> Printf.printf "%d\n" x)
Now the code works but is there a way to accomplish the same thing without building a list(or other data container) to sort/hold the data?
Your function display nearly works without all the meandering of buildList, the only issue is that you are displaying the node data before the data of the left subtree,
My apologies, the description I posted was incomplete. What I really wanted was a next function that provided the next value(from smallest to largest) and a remainder of the values.
I found with a next type function you have to(I have to) build another data container to hold the data.
That being said, I should be able to modify the display function with a list accumulator and get my ordered values.
In this case, you might want to have a look at sequences defined in the Seq module defined in the standard library. They are a kind of lazy list with a next function. In particular, you could try to define a function:
let to_seq: 'a btree -> 'a Seq.t
In this kind of situation, there is often at least two way to store date: either explicitly in a data container or implicitly by storing data in closures or in the stack.
I looked up the Seq docs and though trial and error I think figured out how it works… BTW I never did find the next function.
module MyBtree =
struct
type 'a btree = Empty | Btree of ('a * 'a btree * 'a btree)
let empty = Empty
let rec display toString bt =
match bt with
| Empty -> print_endline "Empty"
| Btree (d, left, right) ->
display toString left;
print_endline (toString d);
display toString right
let rec add data bt =
match bt with
| Empty -> Btree (data, Empty, Empty)
| Btree (d, left, right) ->
if (data < d)
then
Btree (d, add data left, right)
else if (data > d)
then
Btree (d, left, add data right)
else
bt
type 'a buildList = Data of 'a | BNode of 'a btree
let buildLeft bt =
let rec buildLeftAux bt acc =
match bt with
| Empty -> acc
| Btree (d, left, right) ->
buildLeftAux left ((Data d)::(BNode right)::acc) in
buildLeftAux bt []
let to_seq bt =
let bL = buildLeft bt in
let rec to_seq_aux bL =
match bL with
| [] -> Seq.empty
| hd::tl ->
(
match hd with
| Data d -> fun () -> Seq.Cons(d, to_seq_aux tl)
| BNode bt -> to_seq_aux ((buildLeft bt) @ tl)
) in
to_seq_aux bL
end
let b =
List.fold_left
(fun acc elem -> MyBtree.add elem acc)
MyBtree.empty
[10; 1; 9; 2; 8; 3; 7; 4; 6; 5;]
let () =
b
|> MyBtree.display string_of_int
let () = print_endline "\n\n"
let mySeq = MyBtree.to_seq b
let () = Seq.iter (fun x -> Printf.printf "%d " x) mySeq
let rec append left right () = match left () with
| Seq.Nil -> right ()
| Seq.Cons(x, left) -> Seq.Cons(x, append left right)
let to_seq tree () = match tree with
| Empty -> Seq.Nil
| Btree(mid,left,right) ->
append (to_seq left) (append (Seq.return mid) (to_seq right)) ()
Concerning the next function, you can see the sequence itself as a next function for the underlying data or computation.
Note that I thought that your initial code was meandering because your initial stated aim was an iter function; whereas your actual code was quite close of implementing a full zipper as suggested by @toolslive . Zipper or sequence code tend to be more complex to write than internal iterators because they require to give the control to the user.