Home > Back-end >  Exception: Match_failure in an extension of the interpreter to be able to handle the list operations
Exception: Match_failure in an extension of the interpreter to be able to handle the list operations

Time:10-17

I'm trying to implement an extension for the list operations. It checks whether a list is empty or not; if the argument is not a list it should produce an error. I handle the error propagation in the backend with (>>=) function. The empty function I implemented below first checks the value whether is a list using a helper function (list_of_listVal). Then if the list is empty returns true, else returns false. The corresponding code is shown below:

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

However, once I run the top-level I got a warning.

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)

Then when I run the code below it generates the exception:

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

I couldn't figure out how to fix this issue. Could anybody point out how to implement list (v1::v2) in a correct way for the code above?

CodePudding user response:

The problem is that you're destructuring the list into its head and tail (or first element and the rest of the list, respectively), which of course assumes that there is at least one element in the list, hence the warning and the exception when an empty list is encountered.

What do you expect v1 and v2 to be here, when given the empty list?

Furthermore, you're then putting the head and tail together again in the exact same way, without using it in any other way, before comparing it against the empty list. Which can never be true, because you've just constructed a list with at least one element.

The solution then, is to simply not destructure and then immediately reassemble the list. Replace v1::v2 with vs (or any other identifier of your choice). There's also no need to wrap the lists in ListVal, as it's just more indirection.

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

You could then make this even more succinct by using function, which allows pattern matching directly on the function argument without naming it:

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