简体   繁体   English

OCaml选项值树

[英]OCaml option value tree

I've a task to write a function with type 'a btree -> 'a option list that stores the given tree in a list of elements of type 'a option in postfix order (postorder). 我有一个任务要编写一个类型为'a btree -> 'a option list的函数,该函数将给定树存储在后缀顺序(postorder)中类型为'a option的元素列表中。

Internal nodes will be represented by None , external nodes (leaves) with value x will be represented by Some x . 内部节点将由None表示,值为x外部节点(叶)将由Some x表示。

So far it's easy to do for leaves, but how to put it in an 'a option list ? 到目前为止,叶子很容易实现,但是如何将其放入'a option list呢?

type 'a btree = L of 'a | N of 'a btree * 'a btree ;;

let rec store t =
    match t with
        | L x -> Some x
        | N (a,b) -> None ???   
;;

The second match case I know is incorrect, but how to solve it? 我知道第二个匹配项不正确,但是如何解决?

If you look at your first case, you'll see it's also not quite there; 如果您看第一个案例,您会发现它还不存在。 it's returning 'a option , but you want the function to return an 'a option list . 它返回'a option ,但是您希望函数返回'a option list

Clearly you'll be returning a list, so fix that first: 显然,您将返回一个列表,因此请首先解决该问题:

let rec store = function
  | L x -> [Some x]
  | N (a,b) -> [None] (* ??? *)

Now let's fix the second case; 现在让我们解决第二种情况; we want to append None to our output, but before that, we want the nodes of our subtrees: 我们想将None附加到输出中,但是在此之前,我们想要子树的节点:

let rec store = function
  | L x -> [Some x]
  | N (a,b) -> (store a) @ (store b) @ [None]

@ has the type @具有类型

'a list -> 'a list -> 'a list

ie it joins lists together. 即,它将列表连接在一起。 We want to join the list of results from the left subtree, then the right, and then finally the result for this internal node. 我们要加入从左子树开始的结果列表,然后是右子节点,最后是该内部节点的结果列表。

In case someone is interested by this refinement, it is possible to do a bit better, performance-wise, than Len's solution by threading an additional accumulator parameter. 如果有人对这种改进感兴趣,则可以通过线程附加的累加器参数,在性能方面比Len的解决方案好一些。

The idea is to move from a function store : 'a btree -> 'a option list that takes a tree and produce a list to a function store' : 'a btree -> 'a option list -> 'a option list , that adds the element of the tree to an existing list passed as parameter. 这个想法是从功能store : 'a btree -> 'a option list移出的store : 'a btree -> 'a option list采用树并生成列表store : 'a btree -> 'a option list到功能store' : 'a btree -> 'a option list -> 'a option list将树的元素添加到作为参数传递的现有列表中。

let rec store' t acc = match t with
  | L x -> Some x :: acc
  | N (a, b) ->
    store' a (store' b (None :: acc))

With this definition, elements are only added once in the final result list, instead of first being used to build a temporary store a list, then appended a second time to the final result through the (@) operator. 使用此定义,元素仅在最终结果列表中添加一次,而不是首先用于构建临时store a列表,然后通过(@)运算符第二次添加到最终结果。

The parameter order is important because writing t before acc gives an intuition of the final element order in the list: the elements of t will be before the elements already present in acc . 参数order很重要,因为在acc之前写t给出了列表中最终元素顺序的直觉: t的元素将在acc已经存在的元素之前 This allows the N case to read quite naturally: it is easy to see that the result will first have the elements of a , then b , then None , then acc . 这使N情况很自然地读出:很容易看到结果将首先具有abNoneacc的元素。

Finally, you can of course define store in terms of store' : 最后,您当然可以根据store'定义store

let store t = store' t []

It is customary to wrap the first definition inside the second one (if you don't want to expose this "lower-level" function to the users), and to give it the same name as the outer definition (which doesn't conflict as it is not recursive, so does not enter the inner scope): 通常将第一个定义包装在第二个定义内(如果您不希望向用户公开此“低级”功能),并为其指定与外部定义相同的名称(这不会冲突)因为它不是递归的,所以不进入内部作用域):

let store t =
  let rec store t acc = match t with
    | L x -> Some x :: acc
    | N (a, b) ->
      store a (store b (None :: acc))
  in store t []

Of course, whether this definition is "better" than Len's one depends on what your evaluation criterion are. 当然,这个定义是否比Len的定义“更好”取决于您的评估标准。 Len's solution is shorter, easier to read, and maps the original problem more closely. Len的解决方案更短,更易于阅读,并且可以更紧密地映射原始问题。

(You may get the best of both world by using lazy enumerations instead of strict lists, but that's yet another story.) (通过使用惰性枚举而不是严格的列表,您可能会两全其美,但这是另外一回事了。)

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

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