ocaml

How to forward the arguments of a constructor to a function in OCaml?


I have a type with constructors which take many arguments. When pattern matching on a constructor of this type, I would like to forward the arguments as a pack (maybe a tuple?), without having to retype them all.

This is code I would like to write:

type foo_t =
  | FromInt of int * int
  | FromFloat of float

let sum_pair (a, b) =
  a + b
;;

let f foo =
  match foo with
  | FromInt (a, b) as pair -> sum_pair pair
  | FromFloat _ -> 0
;;

The problem here is that pair is typed as foo_t instead of int * int. But sum_pair should expect a pair of ints and not a foo_t.


Solution

  • I think there are a pair of misconceptions about how OCaml works at play here.

    The simplest is that as binds a name just to the thing immediately to the left. Rather, it is greedy. It binds a name to everything to its left.

    E.g.

    # match (1, (2, 3)) with (a, (b, c) as d) -> d;;
    - : int * (int * int) = (1, (2, 3))
    

    As compared to using parentheses to disambiguate and specifically limit what as is binding.

    # match (1, (2, 3)) with (a, ((b, c) as d)) -> d;;
    - : int * int = (2, 3)
    

    Secondly, a set of arguments to a constructor is not a tuple, unless we explicitly make it one. A side note here that while using a constructor looks like a function application, it is not.

    Your FromInt constructor does not take one argument which is a tuple of values, but rather two arguments. The fact that it looks like it's taking a single tuple argument is a side-effect of OCaml syntax.

    As dogbert notes, you can explicitly make it take a single tuple by using parentheses when defining the constructor. At this point the constructor takes one argument which happens to be a tuple containing multiple values.