3

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))
   ;;
jrouquie
  • 4,315
  • 4
  • 27
  • 43
rickmeizter
  • 131
  • 1
  • 7
  • 2
    If you change the first and second occurrences of `n` in your second code snippet to another variable name, but left the others as `n`, the code will still work. Do you understand why? – sepp2k Oct 21 '12 at 09:44
  • @sepp2k yes, I understand I would be using a variable for the material matches with n. What I don't understand is why the first snippet uses "function" (that ,as far as I know, in this context is syntactic sugar for "match x with") and manages to work even though, as I see it, it checks the value of x, and not that of n as the definition of the function would require. – rickmeizter Oct 21 '12 at 09:53

2 Answers2

2

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
jrouquie
  • 4,315
  • 4
  • 27
  • 43
  • The OP didn't ask about the `let`s. – sepp2k Oct 21 '12 at 09:46
  • Thank you for the tip about the let! Now I see it, when using "function" i'm effectively declaring the function takes one more last parameter after the last one declared in the _let_ clause. Should I delete the question? – rickmeizter Oct 21 '12 at 10:01
  • No, keep the question, it could be useful to someone else: http://stackoverflow.com/faq – jrouquie Oct 21 '12 at 10:17
1

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.

Valentin Perrelle
  • 1,303
  • 1
  • 10
  • 17