找到第一个否定条目的两个函数之间的本质区别是什么?

时间:2014-05-19 15:10:42

标签: ocaml

来自 Real World Ocaml ,第24页(参见https://realworldocaml.org/v1/en/html/a-guided-tour.html#for-and-while-loops)。代码是:

# let find_first_negative_entry array =
     let pos = ref 0 in
     while !pos < Array.length array && array.(!pos) >= 0 do
       pos := !pos + 1
     done;
     if !pos = Array.length array then None else Some !pos
  ;;
val find_first_negative_entry : int array -> int option = <fun>
# find_first_negative_entry [|1;2;0;3|];;
- : int option = None
# find_first_negative_entry [|1;-2;0;3|];;
- : int option = Some 1 

# let find_first_negative_entry array =
     let pos = ref 0 in
     while
       let pos_is_good = !pos < Array.length array in
       let element_is_non_negative = array.(!pos) >= 0 in
       pos_is_good && element_is_non_negative
     do
       pos := !pos + 1
     done;
     if !pos = Array.length array then None else Some !pos
  ;;
val find_first_negative_entry : int array -> int option = <fun>
# find_first_negative_entry [|1;2;0;3|];;
Exception: (Invalid_argument "index out of bounds").

作者声称:

  

作为旁注,前面的代码利用了这一事实   &amp;&amp;,OCaml的And运算符,短路。特别是在一个   表达形式expr1&amp;&amp; expr2,expr2只会被评估   expr1评估为true。如果不是那个,那么前面的   函数会导致越界错误。的确,我们可以   通过重写要避免的函数来触发超出范围的错误   短路:“

但我仍然不明白为什么第一个代码工作正常,第二个代码得到例外。我遵守了,两个函数都按预期运行。但我很困惑为什么第二个功能不起作用,因为它使用了&amp;&amp;命令也是如此,并且它也没有处理带有None异常的否定条目。

2 个答案:

答案 0 :(得分:3)

这是评估的顺序。在第一个函数中Term1 && Term2允许&&短路行为来保护我们免受Term2的攻击。在第二个示例中,始终在测试发生之前评估let绑定。因此,对Term2的不良行为没有任何保护。

答案 1 :(得分:1)

!pos >= Array.length array的第一个版本中,无论!pos < Array.length array && whatever的值如何,whatever都必须为真,这就是为什么OCaml无法计算{{1} }。在我们的情况下,如果在whatever时进行评估,array.(!pos) >= 0会引发错误。

但是,在第二个版本中,始终会评估!pos >= Array.length array,即使array.(!pos) >= 0会产生错误。