Tree OCaml选项值树

Tree OCaml选项值树,tree,ocaml,Tree,Ocaml,我的任务是编写一个类型为'abtree->'的函数,它是一个选项列表,将给定的树存储在一个类型为'a option的元素列表中,以后缀顺序(postfix order) 内部节点将由None表示,值为x的外部节点(叶)将由Some x表示 到目前为止,为叶子做这件事很容易,但是如何将它放在选项列表中呢 type 'a btree = L of 'a | N of 'a btree * 'a btree ;; let rec store t = match t with

我的任务是编写一个类型为
'abtree->'的函数,它是一个选项列表
,将给定的树存储在一个类型为
'a option
的元素列表中,以后缀顺序(postfix order)

内部节点将由
None
表示,值为
x
的外部节点(叶)将由
Some x
表示

到目前为止,为叶子做这件事很容易,但是如何将它放在选项列表中呢

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 ???   
;;

我知道的第二个匹配案例是不正确的,但是如何解决它呢?

如果你看第一个案例,你会发现它也不太正确;它正在返回一个选项,但您希望函数返回一个选项列表

很明显,您将返回一个列表,因此首先修复该问题:

let rec store = function
  | L x -> [Some x]
  | N (a,b) -> [None] (* ??? *)
现在让我们修复第二种情况;我们希望在输出中附加
None
,但在此之前,我们需要子树的节点:

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

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

i、 它将列表连接在一起。我们希望从左子树,然后是右子树,最后是该内部节点的结果加入结果列表。

如果有人对这种细化感兴趣,可以通过线程化附加累加器参数,在性能方面比Len的解决方案做得更好

let rec store' t acc = match t with
  | L x -> Some x :: acc
  | N (a, b) ->
    store' a (store' b (None :: acc))
我们的想法是从一个函数
存储区:'a btree->'一个选项列表
,它获取一棵树并生成一个列表,移动到一个函数
存储区:'a btree->'一个选项列表
,它将树的元素添加到作为参数传递的现有列表中

let rec store' t acc = match t with
  | L x -> Some x :: acc
  | N (a, b) ->
    store' a (store' b (None :: acc))
使用此定义,元素只在最终结果列表中添加一次,而不是首先用于构建临时
存储
列表,然后通过
(@)
操作符将第二次附加到最终结果

参数顺序很重要,因为在
acc
之前写入
t
可以直观地知道列表中的最终元素顺序:
t
的元素将位于
acc
中已经存在的元素之前。这使得
N
案例的阅读非常自然:很容易看出,结果将首先包含
a
,然后是
b
,然后是
None
,然后是
acc

最后,您当然可以根据
store'
定义
store

let store t = store' t []
通常将第一个定义封装在第二个定义中(如果您不想向用户公开此“低级”函数),并将其命名为与外部定义相同的名称(这不会冲突,因为它不是递归的,因此不会进入内部范围):

当然,这个定义是否比Len的定义“更好”取决于你的评价标准是什么。Len的解决方案更短,更容易阅读,并且更接近原始问题


(通过使用惰性枚举而不是严格的列表,您可能会获得这两个方面的最佳效果,但这又是另一回事。)

顺便问一下,这是家庭作业吗?如果是这样的话,这并不是一件坏事,但这样说被认为是礼貌的。是的,希望这将是最后一件事:D。我对Ocaml有一些概念是好的,但老实说,这是我以后永远不会使用的东西。你可能会感到惊讶;我在工作中用过很多次,这不是你所说的学术环境。有时候,它正是这份工作的合适工具。我建议你看看@gasche的答案;使用累加器将使这变得更快,并避免列表的附加,每个列表的长度都是O(n)。嗯?这将是一个前序遍历,而不是后序遍历。作为参考,我使用的定义来自。此外,你的改变也无助于让你从一片叶子开始;这就是定义的函数的性质。你可以试着进一步限制它,不允许你从一片叶子开始,但这将是不必要的丑陋。