Ocaml 处理规则树状结构上匹配的代码生成?
我正在开发一个专门的四叉树来做一些生物信息学。qtree的类型包括:Ocaml 处理规则树状结构上匹配的代码生成?,ocaml,camlp4,Ocaml,Camlp4,我正在开发一个专门的四叉树来做一些生物信息学。qtree的类型包括: 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,
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);;
现在,要在这些树上进行匹配,无论是在构建还是行走时,最终都会得到如下结果:
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)) ->
...
你明白了,基本上我需要覆盖所有16个组合(4个子树,可以是空的,也可以是Nd)。这需要大量的输入,而且很容易出错
然而,它是一个非常规则的结构,有助于代码生成。我本来打算用Ruby脚本来生成这段代码,但我想知道这是否可以用campl4或新的ppx风格的“宏”(因为没有更好的术语)?如果是这样的话,我如何从这两个方向中的任何一个开始呢?在功能惯用树中,每个节点都是其子树的根,即使该子树中的每个其他节点都是空的。您需要折叠出显式根定义,并在计数器属性中合并到叶节点:
type base = A | C | G | T ;;
type quad_tree =
| Node of base * int ref * quad_tree * quad_tree * quad_tree * quad_tree
| Empty
但是,在这样做的同时,还可以将该ref设置为显式int,以便使用持久数据结构:
type quad_tree =
| Node of base * int * quad_tree ...
| Empty
根据我对您想要做的事情的理解(每个节点表示与其路径完全匹配的字符串),遍历/构造不必那么复杂——只要让您自己每次创建一个新版本的树即可。有点丑陋的版本:
let shorter str = String.sub 1 ((String.len str) - 1);;
let rec add_str base str = match base with
| Empty ->
let ch = String.get str 0 in
if ch = 'A' then add_str Node('A', 0, Empty, Empty, Empty, Empty) (shorter str)
else if ch = 'C' then add_str Node('C', 0, Empty, Empty, Empty, Empty) (shorter str)
...
| Node(b, v, aa, cc, gg, tt) ->
let len = String.length str in
if len = 0 then Node(b, v + 1, aa, cc, gg, tt) else
let ch = String.get str 0 in
if ch = 'A' then match aa with
| Empty -> Node(b, v, (add_str Empty str), cc, gg, tt)
| Node(b', v', ... , tt') -> add_str Node(b', v', ... , tt') (shorter str)
else if ch = 'C' then match cc with
| Empty -> Node(b, v, aa, (add_str Empty str), gg, tt)
| Node(b', v', ... , tt') -> add_str Node(b', v', ... , tt') (shorter str)
...
你想在这里代表和实现什么?为什么你有两种叶子(
Empty
,Leaf
)?为什么有一个根
与基混合?为什么类型名为base
而不是base
?好问题。在阅读您的评论之前,我将代码中的base更改为base(只是在上面更改了它)。“根”仅用于在顶部标记根节点。Empty和Leaf是不同的东西:Empty是一个初始条件,Leaf将包含一个字符串被看到多少次的计数(这是目的,上面的代码并没有反映这一点,相反accum只是显示树的当前级别)。基本上,它是一个固定长度字符串的树(在本例中是base或k-mers)。已经看到的k-mer被存储在叶子中的次数(我需要将叶子类型更改为:Leaf of base*int ref)