I 'm developing a specialized quad tree for doing some bioinformatics. The types for the qtree are:
type base = A | C | G | T | ROOT ;;
type quad_tree = Nd of bases * quad_tree * quad_tree * quad_tree * quad_tree
| Empty
| Leaf of int ref ;;
let init_quad_tree = Nd(ROOT, Empty,Empty,Empty,Empty);;
let new_node b = Nd(b,Empty,Empty,Empty,Empty);;
Now to do a match on these trees when either constructing or walking you end up with something like:
let rec add_node base k qtree =
let rec aux k' accum qtree' =
if k' = k then
match qtree' with
| Nd(bse, Empty, cc, gg, tt) -> Nd(bse, (Leaf(ref accum)),cc,gg,tt)
| Nd(bse, aa, Empty, gg, tt) -> Nd(bse, aa,(Leaf(ref accum)),gg,tt)
| Nd(bse, aa, cc, Empty, tt) -> Nd(bse, aa,cc,(Leaf(ref accum)),tt)
| Nd(bse, aa, cc, gg, Empty) -> Nd(bse, aa,cc,gg,(Leaf(ref accum)))
| Leaf _ -> qtree'
| Empty -> Leaf(ref accum)
| _ -> qtree'
else
match qtree' with
| Leaf(iref) -> iref := !iref + 1; qtree'
| Nd(bse, Empty,Empty,Empty,Empty) -> (*all empty*)
(
match base with
| A -> Nd(bse,(new_node base),Empty,Empty,Empty)
| C -> Nd(bse,Empty,(new_node base),Empty,Empty)
| G -> Nd(bse,Empty,Empty,(new_node base),Empty)
| T -> Nd(bse,Empty,Empty,Empty,(new_node base))
| _ -> qtree'
)
...
| Nd(bse, Empty,(Nd(_,_,_,_,_) as c),(Nd(_,_,_,_,_) as g),(Nd(_,_,_,_,_) as t)) ->
(
match base with
| A -> Nd(bse,(new_node base),(aux (k'+1) (accum+1) c),(aux (k'+1) (accum+1) g),(aux (k'+1) (accum+1) t))
| C -> Nd(bse,Empty,(aux (k'+1)(accum+1) c),(aux (k'+1)(accum+1) g),(aux (k'+1)(accum+1) t))
| G -> Nd(bse,Empty,(aux (k'+1)(accum+1) c),(aux (k'+1)(accum+1) g),(aux (k'+1)(accum+1) t))
| T -> Nd(bse,Empty,(aux (k'+1)(accum+1) c),(aux (k'+1)(accum+1) g),(aux (k'+1)(accum+1) t))
| _ -> qtree'
)
...
| Nd(bse, (Nd(_,_,_,_,_) as a),(Nd(_,_,_,_,_) as c),(Nd(_,_,_,_,_) as g),(Nd(_,_,_,_,_) as t)) ->
...
You get the idea, basically I need to cover all 16 combinations there (4 subtrees which can either be empty or Nd). That's a lot of typing and it's error prone.
However, it's a very regular structure that would lend itself to code generation. I was going to actually generate this code using a Ruby script, but I'm wondering if this would be possible with campl4 or the new -ppx-style "macros" (for lack of a better term)? And if so, how could I get started in either one of those directions?