Re: letrec/named let

• To: mathgroup at smc.vnet.net
• Subject: [mg56817] Re: letrec/named let
• From: Maxim <ab_def at prontomail.com>
• Date: Fri, 6 May 2005 03:01:37 -0400 (EDT)
• References: <d59kvq\$6f9\$1@smc.vnet.net>
• Sender: owner-wri-mathgroup at wolfram.com

```On Wed, 4 May 2005 05:01:46 +0000 (UTC), Daniel Roy <droy at MIT.EDU> wrote:

> hi.  i'm a lisper/schemer and i'm working with mathematica.  i
> appreciate the lisp-like nature of mathematica but i can't seem to
> easily replicate some of the functionality i like which is forcing me to
> write ugly side-effect code.
>
> for instance, how do you do the equivalent of a "named let" in
> mathematica (NOTE! I know i can take the max of a list, this is just a
> simple example of a named let)
>
> (define (max-of-list lst)
>   (let loop ((lst (cdr lst))
>              (best (car lst)))
>     (if (null? lst)
>         best
>         (loop (cdr lst)
>               (if (> (car lst) best)
>                   (car lst)
>                   best)))))
> (max-of-list '(1 2 3 4 5 2))
>> 5
>
> Here is a mathematica function to compress a sequence numerically.
> here is one attempt using functions where i pass the function to
> itself... there has to be a better way
>
> CompressNumericalSequence[S_] := Module[
>       {C = Function[{C, R, i},
>             If[i < Max[R],
>               If[Length[Position[R, i]] == 0,
>                 C[C, (If[# > i, # - 1, #]) & /@ R, i],
>                 C[C, R, i + 1]],
>               R]]},
>       C[C, S, 1]];
>
> CompressNumericalSequence[{10, 2, 4, 7, 8}]
> {5, 1, 2, 3, 4}
>
> Also, is it possible to do letrec in mathematica?  (essentially, i know
> i can do recursive function declarations at the top level... my question
> is whether i can do them at lower levels?)...
>
> thanks, dan
>
>
>
>

Much of the required information can be found in the Mathematica help,
though not all in one place. From the section 2.7.1 of the Mathematica
Book: "The initial values are always evaluated before the module is
executed." So you could say that

Module[{fact = If[# == 0, 1, #*fact[# - 1]]&}, fact[5]]

works like let, returning 5*fact[4], and

Module[{fact}, fact = If[# == 0, 1, #*fact[# - 1]]&; fact[5]]

works like letrec, returning 120. This is the problem with your definition
of CompressNumericalSequence -- you simply have to move the assignment to
C to the module body, and then you won't need to pass C to itself.
(Another way is to use #0, defining fact as fact = If[# == 0, 1, #*#0[# -
1]]&).

The example with named let can be rewritten like this:

maxoflist = Function[lst,
Module[{loop},
loop = Function[{lst, best},
If[lst === {},
best,
loop[Rest@ lst,
If[First@ lst > best, First@ lst, best]]
]];
loop[Rest@ lst, First@ lst]
]]

A more convenient way can be to write

maxoflist[\$lst_] := Module[{loop},
loop[lst_, best_] :=
If[lst === {},
best,
loop[Rest@ lst,
If[First@ lst > best, First@ lst, best]]
];
loop[Rest@ \$lst, First@ \$lst]
]

In this notation you cannot use the same argument name lst for both
maxoflist and loop though. Also \$lst cannot be used even as a local
variable name, so you cannot write something like

add1[x_] := Module[{helper, val = x},
helper[val_] := Module[{x = 1}, val + x];
helper[val]
]

arguments both in favor and against this model where rules can just
replace Module local variables; personally I cannot see any convincing
arguments in favor of it, and at the same time the drawbacks are quite
clear -- creating nested definitions becomes a pain.

It is also possible to create something similar to function closures:

In[1]:= f = Module[{x1 = 1, x2 = 1, y}, y = x2++&; y[]&]

Out[1]= y\$16[]&

In[2]:= f[]

Out[2]= 1

In[3]:= f[]

Out[3]= 2

In[4]:= {x1\$16, x2\$16}

Out[4]= {x1\$16, 3}

x2\$16 still can be accessed directly, but the only 'honest' way to access
it is to call the function returned from Module, pretty much like Scheme
variables that are visible only to their closures. This is also a simple
way to emulate C-style static local variables. Incidentally, we can see
that x2\$16 was retained after the evaluation of Module, because the top
level kept the link to y\$16 and y\$16 has a link to x2\$16, but x1\$16 was