2
votes

When trying to run the following function in OCaml:

let rec func1 o_list =
    match o_list with
    | [] -> []
    | h::t -> let (nt,inner_list) = h in
      if check_if_clear inner_list then
        [nt,inner_list]::clear_rules
      func1 t
;;

the program outputs an error

Characters 139-141: [nt,inner_list]::clear_rules

Error: This variant expression is expected to have type unit The constructor :: does not belong to type unit

Also you can assume that the function check_if_clear always returns true for now. o_list is a list of pair and pair itself contains an element and a list. So it is something like this [ 'x , ['a,'b,'c]] and clear_rules is just an empty list at first.

2

2 Answers

4
votes

Your original example seems to have a missing semicolon after clear_rules. Once that is inserted and with stubs for the additional functionality, the error message is reproducible. It has the following reason:

The then branch of the if-expression

if check_if_clear inner_list then
    [nt,inner_list]::clear_rules

returns a value of type ('nt_type, 'inner_list_type) list list; this is because [nt, inner_list] constructs a single item list of the pair (nt, inner_list) and then the cons operator :: makes it the head of a list. So, the then branch returns a non-unit type.

Conversely, the else branch (by virtue of not existing) has type unit (i.e. no actual value). But in OCaml, the types for the then and else branch of an expression must match (i.e. be of the same type or subtypes of a common supertype); an if expression without an else branch therefore always has type unit, and so does the then branch of such an expression. Because it doesn't in your case, the compiler tells you that (in a roundabout way), by noting that the cons operator :: has a different type (it creates a list and returns it) than the unit type it had inferred.

I suspect from your comments that your intention was not to create a list, but to perform some action with a side effect. For this, you'll probably need to write that action differently.

2
votes

I managed to solve the problem that I was facing in another way, instead of trying to use some external list, I made my function to return the desired list. Here is the code

let rec func1 o_list clear_list =
match o_list with

| [] -> clear_list
| h::t -> let (nt,inner_list) = h in
if check_if_clear inner_list then
func1 t ([nt,inner_list]::clear_list)
else
func1 t clear_list
;;