Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do variables in pattern matching allow parameter omission?

I'm doing some homework but I've been stuck for hours on something. I'm sure it's really trivial but I still can't wrap my head around it after digging through the all documentation available. Can anybody give me a hand? Basically, the exercise in OCaml programming asks to define the function x^n with the exponentiation by squaring algorithm.

I've looked at the solution:

   let rec exp x = function
    0 -> 1
   | n when n mod 2 = 0  -> let y = exp x (n/2) in y*y
   | n when n mod 2 <> 0 -> let y = exp x ((n-1)/2) in y*y*x
   ;;

What I don't understand in particular is how the parameter n can be omitted from the fun statement and why should it be used as a variable for a match with x, which has no apparent link with the definition of exponentiation by squaring.

Here's how I would do it:

   let rec exp x n = match n with
   0 -> 1
   | n when (n mod 2) = 1 -> (exp x ((n-1)/2)) * (exp x ((n-1)/2)) * x
   | n when (n mod 2) = 0 -> (exp x (n/2)) * (exp x (n/2))
   ;;
like image 243
rickmeizter Avatar asked Dec 05 '25 18:12

rickmeizter


2 Answers

Your version is syntaxically correct, yields a good answer, but is long to execute. In your code, exp is called recursively twice, thus yielding twice as much computation, each call yielding itself twice as much computation, etc. down to n=0. In the solution, exp is called only once, the result is storred in the variable y, then y is squared.

Now, about the syntax,

let f n = match n with
  | 0 -> 0
  | foo -> foo-1

is equivalent to:

let f = function
  | 0 -> 0
  | foo -> foo-1

The line let rec exp x = function is the begging of a function that takes two arguments: x, and an unnammed argument used in the pattern matching. In the pattern matching, the line

 | n when n mod 2 = 0  ->

names this argument n. Not that a different name could be used in each case of the pattern matching (even if that would be less clear):

| n when n mod 2 = 0  -> let y = exp x (n/2) in y*y
| p when p mod 2 <> 0 -> let y = exp x ((p-1)/2) in y*y*x
like image 96
jrouquie Avatar answered Dec 07 '25 17:12

jrouquie


The keyword "function" is not a syntaxic sugar for

match x with

but for

fun x -> match x with

thus

let rec exp x = function

could be replaced by

let rec exp x = fun y -> match y with

which is of course equivalent with your solution

let rec exp x y = match y with

Note that i wrote "y" and not "n" to avoid confusion. The n variable introduced after the match is a new variable, which is only related to the function parameter because it match it. For instance, instead of

let y = x in ...

you could write :

match x with y -> ...

In this match expression, the "y" expression is the "pattern" matched. And like any pattern, it binds its variables (here y) with the value matched. (here the value of x) And like any pattern, the variables in the pattern are new variables, which may shadow previously defined variables. In your code :

let rec exp x n = match n with
  0 -> 1
  | n when (n mod 2) = 1 -> (exp x ((n-1)/2)) * (exp x ((n-1)/2)) * x
  | n when (n mod 2) = 0 -> (exp x (n/2)) * (exp x (n/2))
;;

the variable n in the two cases shadow the parameter n. This isn't a problem, though, since the two variable with the same name have the same value.

like image 30
Valentin Perrelle Avatar answered Dec 07 '25 17:12

Valentin Perrelle



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!