0

I am currently studying OCAML, and have a question about a user-defined if-then such as:

let cond (c,t,e) =
   match c with
   | true -> t
   | false -> e

When used in a factorial function:

let rec fact n =
   cond (n=0,1, n * fact (n-1))

Intuitively, it seems to be correct, but I know it will throw a stack overflow error. Can someone explain to me why this is, and how this user-defined if-then differs from the builtin if-then?

wenjay
  • 29
  • 5
  • As a side-note, don't use pattern-matching to match on values. More about that [here](https://stackoverflow.com/a/47652419/3092183). – Richard-Degenne Dec 20 '17 at 15:53
  • 1
    @RichouHunter , you make a case against pattern-matching on variables (if the writer doesn't understand that he's creating a new binding... even though every other variable-binding construct in the language behaves the same way). `true` and `false` though are values. There's nothing confusing about matching against them. It's the exact same thing as matching against `[]` or `Leaf` or any other variant constructor. – Julian Fondren Dec 25 '17 at 02:03
  • I'd argue that it makes no sense if you don't use any bindings, but I get your point. – Richard-Degenne Jan 03 '18 at 08:43

1 Answers1

6

Basically your user defined conditional is not lazy evaluated. Before the actual match takes place, OCaml tries to evaluate both expressions you pass - for the true and false cases.

Example:

Let's suppose we try to evaluate fact 2.

  • The return value is the expression cond (2=0,1, 2 * fact (2-1)). Before the 3-tuple is passes to cond, it has to be fully evaluated. To do that Ocaml has to evaluate the function fact (2-1).

    • Now we evaluate fact 1. The return value is cond (1=0,1, 2 * fact (1-1)). Again, we need to know the value of fact (1-1), so we compute it recursively.
      • We evaluate fact 0. Here the problem starts to show. The return value is cond (0=0,1, 0 * fact (0-1)), but in order to evaluate the function cond we first have to evaluate its arguments - the 3-tuple. This makes us evaluate fact (0-1)!
        • Then, we are evaluating fact -1...
          • ... fact -2 ... fact -3 ... and the stack overflows :)

The built-in if-then evaluates its arguments lazily: first, it checks whether the condition is true or false, then it accordingly chooses only one branch to evaluate - this behavior is called lazy evaluation.

Actually OCaml has operations lazy and force you could use to avoid this undesirable behavior, but probably it is better just to stick to traditional if.

Radek
  • 846
  • 4
  • 17
  • Could someone tell me please why my answer got -1? I'm just curious, I believe it's correct. – Radek Dec 19 '17 at 01:52
  • I'm not sure why it was downvoted, but I think you are correct. Thank you for the clarification. – wenjay Dec 19 '17 at 01:57
  • I don't understand either so I upvoted you. And at least if someone downvoted he could have commented to explain why. – Lhooq Dec 19 '17 at 04:45