Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect commutative patterns in Ocaml using pattern matching?

I need to detect a commutative pattern in one of my functions. I thought that writing the following will do the work:

let my_fun a b = match a,b with
  (*...*)
  | a,b
  | b,a when is_valid b -> process b  (***)
  (*...*)

This doesn't work and Ocaml complains with this sub-pattern is unused warning for the line marked with (***).

1) Can someone explain to me what this warning try to say and why this doesn't work?

2) How can I actually write this elegantly without using if then else given the fact that I want to now which argument is_valid?

2) Is it possible to get the intended functionality using only pattern matching and without repeating when is_valid b -> process b as it happens bellow?

let my_fun a b = match a,b with
  (*...*)
  | a,b when is_valid b -> process b
  | b,a when is_valid b -> process b 
  (*...*)

Edit:

In my concrete example a and b are pairs. The function is a bit more complicated but the following will illustrate the case:

let f a b = match a,b with
  | (a1,a2),(b1,b2)
  | (b1,b2),(a1,a2) when b1 = b2 -> a1 + a2

Calling f (1,1) (1,2) will yield pattern match failed. I know understand why (thanks to the answers bellow) and I understand how I can make it work if I have different constructors for each element (as in Ashish Agarwal's answer). Can you suggest a way to make it work in my case?

like image 748
Calin Avatar asked May 09 '11 15:05

Calin


People also ask

How does pattern matching work in OCaml?

Pattern matching comes up in several places in OCaml: as a powerful control structure combining a multi-armed conditional, unification, data destructuring and variable binding; as a shortcut way of defining functions by case analysis; and as a way of handling exceptions.

Can you pattern match strings OCaml?

There is a way to match strings as a list of characters, using a function from SML (which you can write in OCaml) called 'explode' and 'implode' which --respectively -- take a string to a char list and vice versa.


1 Answers

The matching works by first matching the pattern, and if that succeedes, then by evaluating the condition with the attached environment from that pattern match. Since a,b will always bind, this is the only case used, and the compiler is correctly reporting that b,a is never used. You'll have to repeat that line,

let my_fun a b = match a,b with
  | a,b when is_valid b -> process b
  | b,a when is_valid b -> process b

Your method could work if you didn't perform the match with variables but to some variant, for example,

let my_fun a b = match a,b with
  | a, `Int b
  | `Int b, a when is_valid b -> process b

Edit: Think of the multiple patterns using one guard as a subexpression,

let my_fun a b = match a,b with
  | ((a,b) | (b,a)) when is_valid b -> process b

You'll see this exemplified in the definition for patterns. It's really one pattern, composed of patterns, being matched.

like image 193
nlucaroni Avatar answered Sep 27 '22 22:09

nlucaroni