异常:Match_failure 在解释器的扩展中能够处理 OCaml 中的列表操作

Exception: Match_failure in an extension of the interpreter to be able to handle the list operations in OCaml

我正在尝试实现列表操作的扩展。它检查列表是否为空;如果参数不是一个列表,它应该产生一个错误。我使用 (>>=) 函数在后端处理错误传播。我在下面实现的空函数首先使用辅助函数 (list_of_listVal) 检查值是否是列表。然后如果列表为空 returns true,否则 returns false。对应代码如下:

  | Empty(e1) ->
    eval_expr e1 >>= 
    list_of_listVal >>= fun (v1::v2) ->
    if ( ListVal ([]) = ListVal (v1::v2) )
      then return @@ BoolVal(true)
      else return @@ BoolVal(false)

但是,一旦我 运行 顶层,我就收到了警告。

Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
File "src/interp.ml", lines 88-91, characters 24-35:
88 | ........................fun (v1::v2) ->
89 |     if ( ListVal ([]) = ListVal (v1::v2) )
90 |       then return @@ BoolVal(true)
91 |       else return @@ BoolVal(false)

然后当我 运行 下面的代码生成异常时:

utop # interp "empty?(emptylist)";;
Exception: Match_failure ("src/interp.ml", 88, 24).

我不知道如何解决这个问题。有人能指出如何以正确的方式为上面的代码实现列表 (v1::v2) 吗?

问题是您正在将列表解构为头部和尾部(或分别为第一个元素和列表的其余部分),这当然假设列表中至少有一个元素,因此遇到空列表时的警告和异常。

当给定空列表时,您希望 v1v2 在这里是什么?

此外,在将它与空列表进行比较之前,您将以完全相同的方式再次将头部和尾部放在一起,而不以任何其他方式使用它。这永远不可能是真的,因为您刚刚构造了一个至少包含一个元素的列表。

那么解决方案就是不解构然后立即重新组合列表。将 v1::v2 替换为 vs(或您选择的任何其他标识符)。也没有必要将列表包装在 ListVal 中,因为它只是更间接。

fun vs ->
  if vs = [] then
    return (BoolVal true)
  else
    return (BoolVal false)

然后您可以使用 function 使其更加简洁,它允许直接在函数参数上进行模式匹配而无需命名它:

function | [] -> return (BoolVal true)
         | _ -> return (BoolVal false)