【问题标题】:OCaml, unexpected behavior with refs and treesOCaml,引用和树的意外行为
【发布时间】:2017-08-01 12:53:36
【问题描述】:

我试图为树的每个元素分配一个数字。我认为使用refs 会使任务更容易,但我遇到了一个奇怪的行为:分配的数字不是唯一的,也没有出现明确的模式。我设法修复了这个错误(添加了let unboxed = !second_ref in 行),但我不明白发生了什么。

输出控制台中的第一棵树只是确保print_tree 函数输出它应该输出的内容。

但是,第二次打印的预期输出应该与第三棵树的输出完全相同。我错过了什么?

type ('a, 'b) tree =
  | Node of 'a * ('a, 'b) tree * ('a, 'b) tree
  | Leaf of 'b

let print_tree tree string_of_node string_of_leaf  =
  let rec print indent tree =
    match tree with
    | Leaf (l) -> print_string (indent^" -> "^string_of_leaf(l)^"\n")
    | Node (n, left, right) ->
      Printf.printf "%s-----------\n" indent;
      print (indent ^ "|         ") left;
      Printf.printf "%s%s\n" indent (string_of_node(n));
      print (indent ^ "|         ") right;
      Printf.printf "%s-----------\n" indent
  in print "" tree 

let myTree = Node(1,Node(2,Leaf(3),Leaf(4)),Node(5,Leaf(6),Leaf(7))) ;;

let first_ref = ref 0 ;;
let rec bug tree = 
  first_ref := !first_ref+ 1;
  match tree with
  |Leaf(a) -> Leaf(!first_ref)
  |Node(n,l,r) -> Node(!first_ref, bug l, bug r) ;;

let second_ref = ref 0 ;;
let rec bug_fixed tree = 
  second_ref := !second_ref + 1;
  let unboxed = !second_ref in
  match tree with
  |Leaf(a) -> Leaf(unboxed)
  |Node(n,l,r) -> Node(unboxed, bug_fixed l, bug_fixed r) ;;


let bug_tree = bug myTree ;;
let bug_fixed_tree = bug_fixed myTree ;;

print_tree myTree string_of_int string_of_int ;
print_tree bug_tree string_of_int string_of_int ;
print_tree bug_fixed_tree string_of_int string_of_int ;

输出如下:

-----------
|         -----------
|         |          -> 3
|         2
|         |          -> 4
|         -----------
1
|         -----------
|         |          -> 6
|         5
|         |          -> 7
|         -----------
-----------
-----------
|         -----------
|         |          -> 7
|         7
|         |          -> 6
|         -----------
7
|         -----------
|         |          -> 4
|         4
|         |          -> 3
|         -----------
-----------
-----------
|         -----------
|         |          -> 7
|         5
|         |          -> 6
|         -----------
1
|         -----------
|         |          -> 4
|         2
|         |          -> 3
|         -----------
-----------

【问题讨论】:

  • 这可能是题外话,但你对tree 类型的定义让我感到困惑。叶子的类型可能与节点不同?

标签: debugging tree ocaml ref


【解决方案1】:

在您的 bug 函数中,有这个有问题的表达式:

Node(!first_ref, bug l, bug r)

其行为取决于参数的评估顺序:bug lbug r 递增 first_ref,因此传递的值可能不是您想要的。

您可以通过以下方式强制订单:

let v = !first ref in
let new_l = bug l in
let new_r = bug r in
Node (v, new_l, new_r)

【讨论】:

  • 只是为了给这个答案添加一点上下文。从理论上讲,由于没有副作用,在纯函数式语言中,评估顺序并不重要。当然,使用引用打破了这种情况,因此使用了本地绑定技巧。值得注意的是,OCaml 中没有指定求值顺序,这符合语言的函数性质。
  • @RichouHunter,OCaml 远非纯粹,除了可变状态之外还有很多其他效果,例如异常、非终止、I/O 等。所以恕我直言,没有理由不指定评估顺序。这是它最烦人的陷阱之一。
  • 我完全同意,@AndreasRossberg。不过,我想知道现在指定它会对现有的实现和代码库产生什么影响。
  • @RichouHunter,理论上,它只会影响当前有问题的程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-16
  • 2010-12-03
相关资源
最近更新 更多