Search code examples
ocamlstrong-typing

Function with multiple return types: is it possible?


I have the following bit of code, which I'd like to return either a boolean or a tuple. (The functions isvariable and dont_care both return booleans, fyi)

let match_element (a, b) =
if a = b then true
else if (dont_care a) || (dont_care b) then true
else if (isvariable a) then (a, b)
else if (isvariable b) then (b, a)
else false;;

Currently, it raises the following error:

Is there any way of resolving this?

This expression has type 'a * 'b
but an expression was expected of type bool

(This function is based on instructions for a Python program, and I'm not sure if it's possible in OCaml. )


Solution

  • What you want is, very roughly speaking, ad-hoc polymorphism or overloading. It is impossible in OCaml, and more importantly, we do not want to have it in OCaml.

    If you want to have a function which returns multiple types, then you have to define a new "sum" type which can express these types: here, you want to return a boolean or a tuple, so a new type which means "a boolean or a tuple". In OCaml we define such a type like:

    type ('a, 'b) t = Bool of bool
                    | Tuple of 'a * 'b
    

    Using this new sum type your code should look like:

    type ('a, 'b) t = 
      | Bool of bool
      | Tuple of 'a * 'b
    
    let match_element (a, b) =
      if a = b then Bool true
      else if dont_care a || dont_care b then Bool true
      else if is_variable a then Tuple (a, b)
      else if is_variable b then Tuple (b, a)
      else Bool false;;
    

    The type t here with two parameters ('a and 'b) can be too general for your purpose, but I cannot guess what you want to do from the context. There may be nicer type definition which suits with your intention, like:

    type element = ... (* Not clear what it is from the context *)
    
    type t =
      | I_do_not_care        (* Bool true in the above definition *)
      | I_do_care_something  (* Bool false in the above definition *)
      | Variable_and_something of element * element  (* was Tuple *)