List Info

Thread: "ocaml_beginners"::[] tail recursion




"ocaml_beginners"::[] tail recursion
country flaguser name
United States
2008-07-03 15:03:46

I am reading about f^n ...

# let rec iter n f =
if n = 0 then (fun x -> x) else o f (iter (n-1) f);;

where
# let o f g = fun x -> f(g(x));;

which they rewrite as...

# let rec iter = fun n f x ->
if n = 0 then x else f(iter (n-1) f x);;

Would this tail recursive form be more common in practice?

# let rec iter = fun n f x ->
if n = 0 then x else iter (n-1) f (f x);;

__._,_.___
.

__,_._,___
Re: "ocaml_beginners"::[] tail recursion
country flaguser name
France
2008-07-03 14:09:35

Hi Marlene,

> Would this tail recursive form be more common in practice?

I'm not experienced enough to accurately answer but I prefer the former that suppresses one parameter.
However, the problem with this elegant parameters elimination is the function sometimes becomes undocumented by the lacking parameters names.

> # let rec iter = fun n f x ->
> if n = 0 then x else iter (n-1) f (f x);;
Please why do you use 'fun ->' instead of this simpler writing :

let rec iter n f x = if n = 0 then x else iter (n-1) f (f x)

?

Regards,

Fabrice

__._,_.___
.

__,_._,___
Re: "ocaml_beginners"::[] tail recursion
country flaguser name
United Kingdom
2008-07-03 18:20:10

>I am reading about f^n ...
>
> # let rec iter n f =
> if n = 0 then (fun x -> x) else o f (iter (n-1) f);;
>;
> where
> # let o f g = fun x -> f(g(x));;
>
> which they rewrite as...
>
> # let rec iter = fun n f x ->
> if n = 0 then x else f(iter (n-1) f x);;
>;
> Would this tail recursive form be more common in practice?
>
> # let rec iter = fun n f x ->
> if n = 0 then x else iter (n-1) f (f x);;

Or:

let rec nest n f x =
if n=0 then x else nest (n-1) (f x)

Absolutely, yes. As a generic library function it is essential that you
write it in tail recursive form.

Cheers,
Jon.

__._,_.___
.

__,_._,___
Re: "ocaml_beginners"::[] tail recursion
country flaguser name
United Kingdom
2008-07-03 18:34:31

>> Would this tail recursive form be more common in practice?
>
> I'm not experienced enough to accurately answer but I prefer the former
> that suppresses one parameter.

Actually that (eta reduction, IIRC) is a dangerous practice in impure
languages like OCaml because it changes when the expressions are evaluated.
In this case, eta reducing by removing the "x" arguments from both sides of
the definition causes the function to partially evaluate sooner, yielding a
closure that encapsulates "n" nested function applications. If you remove
all arguments that were otherwise deferring the evaluation then you can even
change the type of the expression from polymorphic to monomorphic, where the
non-generalized type variable (e.g. '_a) will be ossified at first use or
even resulting in a type error if it tries to escape a compilation unit.
There is also the danger of altering the meaning of the program.

Consider this:

let rec eval state = function
| Int n -> n
| Add(f, g) -> eval state f + eval state g

You might factor out the common "eval state"; subexpression:

let rec eval state expr =
let eval = eval state in
match expr with
| Int n -> n
| Add(f, g) -> eval f + eval g

Then you might be tempted to revert back to using "function" to avoid the
superfluous "expr" argument that was not needed before:

let rec eval state =
let eval = eval state in
function
| Int n -> n
| Add(f, g) -> eval f + eval g

But you have now created an infinite loop with "eval state"; recursing
indefinitely!

Specifying all arguments in a definition is generally safer and more
efficient in OCaml.

Cheers,
Jon.

__._,_.___
.

__,_._,___
[1-4]

about | contact  Other archives ( Real Estate discussion Medical topics )