English version
Accueil     Ŕ propos     Téléchargement     Ressources     Contactez-nous    

Ce site est rarement mis ŕ jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml ŕ l'adresse ocaml.org.

Browse thread
Parameter evaluation order
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2005-08-22 (16:50)
From: Damien Doligez <damien.doligez@i...>
Subject: Re: [Caml-list] Parameter evaluation order
On Aug 20, 2005, at 00:21, Márk S. Zoltán wrote:

> But I do think that currying + strictness + side-effects => left-to- 
> right evaluation order.

The problem (and historical reason for OCaml's unspecified order) is  

currying + side-effects + left-to-right evaluation order => inefficiency

Suppose you want to evaluate a curried function call in left-to-right  
f e1 e2 e3 e4

You must evaluate f first, then e1.  Then you must apply f to e1, giving
a new function g1.  Then you must evalue e2, then apply f1 to e2, giving
f2, etc.

That's because f might do some side effects between its arguments.   
all functions are unary and you must encode n-ary functions with  
there is no way to specify (within the type system) a function that is
safe for efficient application.  You would like to evaluate f, then e1,
then e2, then e3, then e4, then the whole application at once, but you

So the programmer wants to write a function call with 4 arguments, but
he cannot, and his code ends up doing 4 separate function calls, which
is a lot of overhead.

Hence there needs to be a notion of n-ary function at some point.  If  
in the type system, then within the compiler, which has to guess which
functions the programmer wants to use as n-ary, and which ones as  
and translate between the two versions as needed.  Fortunately, it's not
hard to guess, since true curried functions are almost nonexistent,  
so you
can't go wrong (efficiency-wise) if you always guess "n-ary".  The only
drawback is that you have to work harder to implement higher-order
functions, and you lose some efficiency there.

> ==== ordertest.ml =====
> let f a b c d = ()
> let () =
>  let ff1 = f (print_string "1") in
>  let ff2 = ff1 (print_string "2") in
>  let ff3 = ff2 (print_string "3") in
>  ff3 (print_string "4");
>  print_newline ()
> let () =
>  let f2 = f (print_string "1") (print_string "2")
>  in f2 (print_string "3") (print_string "4") ;
>  print_newline ()
> let () =
>  f
>    (print_string "1")
>    (print_string "2")
>    (print_string "3")
>    (print_string "4");
>  print_newline ()
> ==============

You'll see the problem if you try replacing your definition of f with
the following:

let f a =
   print_string "a";
   fun b ->
   print_string "b";
   fun c ->
   print_string "c";
   fun d ->
   print_string "d";

Note the really strange results when compiled with ocamlopt.

All these problems disappear when you evaluate in right-to-left order,
which corresponds to a nice optimization in the original ZAM: evaluate
and push each argument on the stack, then jump to the function code.

-- Damien