Re: Omitting eta-expansion gives a wrong answer

"Victor Lanvin [email protected] [ocaml_beginners]" <[email protected]> Fri, 26 Aug 2016 13:11:03 +0000
Newsgroups gmane.comp.lang.ocaml.beginners
Message-ID <CAPW4PBJKh5X2ukAvSjby_4TLPmCq3d87U9Rmxkwyz=WUineEMg@mail.gmail.com>
Le ven. 26 août 2016 à 13:13, [email protected] [ocaml_beginners] <
[email protected]> a écrit :

>
>
> There are well-known situations in OCaml where the programmer must write
> some eta-expansion by hand to get what he wants (for example, see FAQ -
> Core language)
> <http://caml.inria.fr/resources/doc/faq/core.en.html#eta-expansion>
> FAQ - Core language
> <http://caml.inria.fr/resources/doc/faq/core.en.html#eta-expansion>
> You imperatively need to enclose between parens a pattern matching which
> is writt...
> View on caml.inria.fr
> <http://caml.inria.fr/resources/doc/faq/core.en.html#eta-expansion>
> Preview by Yahoo
>
> Recently, I encountered an example where not writing the eta-expansion
> results not in a type error, but in a wrong answer! I have never seen this
> mentioned in the manual or elsewhere, and I'm curious to know if anyone has
> more feedback on this (in particular, can anyone explain in detail what ma
> kes the Ocaml interpreter give a wrong answer ?)
>
> Consider the following code snippet :
>
> let jimmy x=
>   let _=(print_string"Hello I am Jimmy\n";flush stdout) in
>   true;;
>
> let bart x=
>   let _=(print_string"Hello I am Bart\n";flush stdout) in
>   true;;
>
>
> let decider=ref(false);;
>
> let jimmy_or_bart t=
>   if (!decider)
>   then jimmy t
>   else bart t;;
>
> let example1=jimmy_or_bart ();;
> decider:=true;;
> let example2=jimmy_or_bart ();;
>
>
> As expected, the computation of example1 will output "I am Bart" and
>
> and example2 "I am Jimmy". But if you remove the eta-expansion in the
> definition of jimmy_or_bart :
>
>
>
>
> let jimmy_or_bart=
>   if (!decider)
>   then jimmy
>   else bart;;
>
>
> then both examples will output
> "I am Bart".
>

Hi,

This is actually the expected behaviour. When you input a term in the
interpreter, it immediatly tries to reduce it according to some reduction
rules, until the term is in its simplest possible form (i.e. a value).
A term is considered a value --and is therefore not reducible anymore-- if
it is a function or a constant (to keep it simple). Moreover, in OCaml (and
most programming languages), the body of a function is not evaluated until
the function is applied to some arguments.

Now, consider your first example. The term jimmy_or_bart is defined as a
function that takes one parameter. Therefore, the body of the function
jimmy_or_bart (the if...then...else statement) is not reduced.
When the function is applied to unit, the body can be evaluated. In
example1, !(decider) evaluates to false, therefore the if condition reduces
to the second branch : "bart ()"; which outputs "I am Bart".
If you change the value of "decider" and reapply the function, the
interpreter will once again evaluate !(decider); but this time it will
evaluate to "true", and the if condition will reduce to the first branch.

In the second example, the term [if (!decider) then jimmy else bart] is not
a function nor a constant, therefore it can be reduced ! When you input
this term, the interpreter will directly evaluate the value of !decider
--which is false--, and reduce the if condition. That is,

let jimmy_or_bart =
  if !decider
  then jimmy
  else bart

actually reduces to :

let jimmy_or_bart = bart

Now, if you inline the definition of bart, you basically get :

let jimmy_or_bart = fun x ->
  let _ = (print_string "Hello I am Bart\n";flush stdout) in
  true;;

which explains the behavior you remarked. "decider" does not appear in the
value of jimmy_or_bart anymore.

I hope I have been of some help, sorry if I was not clear enough.

--
Victor Lanvin