简体   繁体   English

OCaml函数与数据类型树

[英]OCaml function with data type tree

We are give a tree that contains two types of elements. 我们给出一个包含两种元素的树。 It is defined with the following data-structure. 它由以下数据结构定义。

type ( 'a , 'b ) tree =
   Empty
   | Vertexa of 'a * ( 'a , 'b ) tree list
   | Vertexb of 'b * ( 'a , 'b ) tree list

Write a function split: ('a,'b) tree -> 'a list * 'b list, that saves all elements of type 'a to the first list and all elements of type 'b in the second list. 编写一个函数split:('a,'b)tree - >'list *'b list,它将'a'类型的所有元素保存到第一个列表,将所有类型'b'的元素保存在第二个列表中。

I had an idea of doing this recursively but I am kind of stuck on this. 我有一个想法,递归地做这个,但我有点坚持这个。 I will attach my attempt even though it does not work at all :/ 即使它根本不起作用,我也会附上我的尝试:/

let rec one drevo_list=
    match drevo_list with
   | [Empty]->Empty 
   | Empty::tl -> one tl
   | Vertexa(a,b)::tl -> Vertexa(a,b@tl) 
   | Vertexb(a,b)::tl -> Vertexb(a,b@tl) 

This function turns a list into a tree. 此功能将列表转换为树。 I needed it for the recursion, since the second parametar in Vertexa or Vertexb is a list. 我需要它用于递归,因为Vertexa或Vertexb中的第二个参数是一个列表。 And this works But the recursion part does not. 这工作但但递归部分没有。

let rec split drevo=
   match drevo with
   | Empty -> [],[]
   | Vertexa(a,b)-> split (one b)
   | Vertexb(a,b)-> split (one b)

This part does not work and I have no idea how to finish it. 这部分不起作用,我不知道如何完成它。 Does any one have an idea how to finish this? 有没有人知道如何完成这个?

You don't need the drevo_list function to solve this problem. 您不需要drevo_list函数来解决此问题。 It will actually lead you in a wrong direction. 它实际上会引导你走错方向。

You need to use List.map to apply your split on a list of trees. 您需要使用List.map将拆分应用于树列表。 You will get a value of ('a list * 'b list) list type. 您将获得('a list * 'b list) list类型的值。 Now you need a helper function concat_pairs that will flatten this value into a pair of type 'a list * 'b list (cf, standard concat function). 现在你需要一个帮助函数concat_pairs ,它将这个值展平为一对类型'a list * 'b list (参见标准concat函数)。 To implement this function you may use List.fold_left . 要实现此功能,您可以使用List.fold_left The rest is trivial. 其余的都是微不足道的。

Note, of course this is a greedy solution. 注意,当然这是一个贪心的解决方案。 When you finished with it, you may try to find a better solution, that is more efficient and tail recursive. 完成后,您可能会尝试找到更好的解决方案,更高效,尾递归。

There are at least two parts of this function that make it difficult to write: 这个函数至少有两个部分难以编写:

  1. A function that returns a pair of lists needs to pack and unpack its return value in each recursive step through eg helper functions, match statements or let bindings. 返回一对列表的函数需要在每个递归步骤中打包和解包其返回值,例如辅助函数,匹配语句或let绑定。 One way would be to write a function that inserts an element into a list inside a pair: 一种方法是编写一个函数,将一个元素插入一对内的列表中:

     let insertA a (xs, ys) = (a::xs, ys) let insertB b (xs, ys) = (xs, b::ys) 
  2. A function that is recursive over both a tree type and an embedded list type requires the combination of two recursion patterns. 对树类型和嵌入列表类型递归的函数需要两个递归模式的组合。 This can be solved using either a set of mutually recursive functions, or using higher-order combinators for the lists. 这可以使用一组相互递归的函数或使用列表的高阶组合器来解决。 Here is an outline of a solution using the former strategy: 以下是使用前一策略的解决方案概述:

     let rec split s = match s with | Empty -> ([], []) | Vertexa (a, ts) -> (* if we had just one t: insertA a (split t) *) | Vertexb (a, ts) -> (* if we had just one t: insertB b (split t) *) 

    So you need a function splitMany : ('a, 'b) tree list -> ('a list, 'b list) that may call back on split for each of its individual trees. 因此,您需要一个函数splitMany : ('a, 'b) tree list -> ('a list, 'b list) ,可以为每个单独的树回调split

     and rec splitMany ts = match ts with | [] -> ([], []) | (t:ts') -> (* merge (split t) with (splitMany ts') *) 

    For the higher-order function approach, you can avoid the explicit mutual recursion by having the function pass itself to a set of higher-order functions and thus not entangle it in the implementation of the higher-order functions: 对于高阶函数方法,可以通过让函数将自身传递给一组高阶函数来避免显式的相互递归,从而不会在高阶函数的实现中纠缠它:

     let rec split s = match s with | Empty -> [],[] | Vertexa (a, ts) -> insertA (concat_pairs (map split ts)) | Vertexb (a, ts) -> insertB (concat_pairs (map split ts)) 

    where concat_pairs is ivg's invention. 其中concat_pairs是ivg的发明。

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

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