来自 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异常的否定条目。
答案 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
会产生错误。