简体   繁体   English

Ocaml递归:模式匹配

[英]Ocaml recursion: Pattern Matching

I am trying to write to recursive fn that changes a unlabelled tree to a labelled tree with the use of a helper function. 我试图写入递归fn,使用辅助函数将未标记的树更改为标记的树。

required info: 必填信息:

type nucleotide = 
| G | C
| A | T 

type helix = nucleotide list

type tree = 
| Leaf of helix 
| Node of tree * tree

type labeled_tree =
| LLeaf of helix
| LNode of labeled_tree * helix * labeled_tree

This is the helper function: 这是辅助函数:

let rec guess_parent_helix (x1: helix) (x2: helix) : helix =
 begin match (x1, x2) with
 ([], []) -> []
 | (h1 :: t1, h2 :: t2) ->
   (if h1 = h2 then h1 else A) :: guess_parent_helix t1 t2
 | _ -> failwith "invalid input: x1 and x2 have unequal lengths"
 end

I have written the following function but am unable to compile as it says I have not exhausted the pattern matching : Node( (Node(_ , _ ),_) ). 我编写了以下函数,但无法编译,因为它说我没有用尽模式匹配:Node((Node(_,_),_))。 What I do not understand is, how is this not included in the Node(rt,lt) pattern match: 我不明白的是,这不包括在Node(rt,lt)模式匹配中:

let rec add_ancestor_labels (r: tree) : labeled_tree =
  begin match r with
    | Leaf x -> LLeaf x
    | Node (lt,rt) -> 
        begin match r with
        | Leaf x -> LLeaf x
        | Node (Leaf[m], Leaf[n]) -> 
            LNode (add_ancestor_labels lt, guess_parent_helix [m] [n], add_ancestor_labels rt) 
        end
    end

It's the inner match that's incomplete. 这是不完整的内在比赛。 The outer match is fine. 外围的比赛很好。

Update 更新

The code as it stands doesn't make a lot of sense. 现在的代码没有多大意义。 After matching r and finding that it's an internal node, you match r again. 匹配r并发现它是一个内部节点后,再次匹配r There's no need to do this, you already know it's an internal node. 没有必要这样做,你已经知道它是一个内部节点。

It's hard to give specific advice since I don't know what the labels are supposed to look like. 由于我不知道标签应该是什么样子,所以很难给出具体的建议。 Here is some code that sets each label to the concatenation of the nucleotides below it: 这里有一些代码将每个标签设置为它下面的核苷酸的连接:

let labeled_tree_of_tree tree =
    let rec go t =
        match t with
        | Leaf x -> (x, LLeaf x)
        | Node (lt, rt) ->
            let (llabel, llt) = go lt in
            let (rlabel, lrt) = go rt in
            let label = llabel @ rlabel in
            (label, LNode (llt, label, lrt))
    in
    let (_, ltree) = go tree in
    ltree

Maybe this will give a feel for what your code might look like. 也许这会让你感受到代码的外观。 No doubt it will be more complicated than this. 毫无疑问,它会比这更复杂。

Exhaustiveness checking only applies to the cases of a single match. 穷举检查仅适用于单个匹配的情况。 Information about which cases are possible will not be propagated to nested matches, which can occasionally lead to some "impossible" cases. 关于哪些情况可能的信息将不会传播到嵌套匹配,这有时会导致一些“不可能”的情况。

Where possible, it is better to extend the match with additional cases like this: 在可能的情况下,最好使用以下附加案例扩展匹配:

let rec add_ancestor_labels = function
  | Leaf x -> LLeaf x
  | Node (Leaf x, Leaf y) ->
     LNode (LLeaf x,
            guess_parent_helix x y,
            LLeaf y)
  | Node (Leaf x, Node (l, r)) ->
     LNode (LLeaf x,
            ...,
            LNode (add_ancestor_labels l,
                   ...,
                   add_ancestor_labels r))
  | Node (Node ..., Leaf x) -> ...
  | Node (Node ..., Node ...) -> ...

An alternative to repeating the outermost constructor is to bind the arguments to variables and then match on those: 重复最外层构造函数的另一种方法是将参数绑定到变量,然后匹配这些变量:

let rec add_ancestor_labels = function
  | Leaf x -> LLeaf x
  | Node (l, r) ->
     begin
       match l, r with
        | ...
     end

Finally, note that Leaf [m] only matches leaves that have helixes of length 1 - leaves with helixes of other lengths are unhandled. 最后,请注意Leaf [m]仅匹配长度为1的螺旋叶 - 其他长度的螺旋叶未处理。 It's not clear whether this is what you intended, but exhaustiveness checking will warn if you forget to handle the case of leaves of other lengths. 目前尚不清楚这是否符合您的意图,但如果您忘记处理其他长度的叶子,则详尽无遗检查会发出警告。

The warning messages that OCaml gives you for nonexhaustive matches should include some of the missing cases, so do read them carefully. OCaml为非穷举匹配提供的警告消息应包括一些缺失的情况,因此请仔细阅读。

As for your function, I think it would be written like this: 至于你的功能,我认为会这样写:

let add_ancestor_labels tree =
  let rec label = function
    | Leaf x -> x, LLeaf x
    | Node (left, right) ->
       let llabel, ltree = label left in
       let rlabel, rtree = label right in
       let l = guess_parent_helix llabel rlabel in
       l, LNode (ltree, l, rtree) in
  snd (label tree)

(Which is very similar to Jeffrey's suggestion.) (这与杰弗里的建议非常相似。)

 let rec add_ancestor_labels (r: tree) : labeled_tree =
begin match r with
| Leaf x -> LLeaf x
| Node (lt,rt) -> 
    begin match (lt, rt) with
    | (Leaf m, Leaf n) -> 
        LNode (LLeaf m, guess_parent_helix m n, 
        LLeaf n) 
    | (lt,Leaf n)-> LNode(add_ancestor_labels lt, 
    guess_parent_helix (helix_of_tree (add_ancestor_labels lt)) n, LLeaf n)
    | (Leaf m,rt)->LNode(LLeaf m, guess_parent_helix 
    (helix_of_tree(add_ancestor_labels rt)) m, add_ancestor_labels rt)
    | (_,_)-> failwith"invalid input"
    end
end

Managed to finish it. 管理完成它。 Thank you for your help. 谢谢您的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM