Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a variable in pattern matching in Ocaml or F#

I have a function of the form

'a -> ('a * int) list -> int

let rec getValue identifier bindings = 
  match bindings with
  | (identifier, value)::tail -> value
  | (_, _)::tail -> getValue identifier tail
  | [] -> -1

I can tell that identifier is not being bound the way I would like it to and is acting as a new variable within the match expression. How to I get identifier to be what is passed into the function?

Ok! I fixed it with a pattern guard, i.e. | (i, value)::tail when i = indentifier -> value but I find this ugly compared to the way I originally wanted to do it (I'm only using these languages because they are pretty...). Any thoughts?

like image 291
Sandy Vanderbleek Avatar asked Mar 04 '10 21:03

Sandy Vanderbleek


1 Answers

You can use F# active patterns to create a pattern that will do exactly what you need. F# supports parameterized active patterns that take the value that you're matching, but also take an additional parameter.

Here is a pretty stupid example that fails when the value is zero and otherwise succeeds and returns the addition of the value and the specified parameter:

let (|Test|_|) arg value = 
  if value = 0 then None else Some(value + arg)

You can specify the parameter in pattern matching like this:

match 1 with
| Test 100 res -> res // 'res' will be 101

Now, we can easily define an active pattern that will compare the matched value with the input argument of the active pattern. The active pattern returns unit option, which means that it doesn't bind any new value (in the example above, it returned some value that we assigned to a symbol res):

let (|Equals|_|) arg x = 
  if (arg = x) then Some() else None

let foo x y = 
  match x with
  | Equals y -> "equal"
  | _ -> "not equal"

You can use this as a nested pattern, so you should be able to rewrite your example using the Equals active pattern.

like image 137
Tomas Petricek Avatar answered Sep 30 '22 19:09

Tomas Petricek