MathGroup Archive 2005

[Date Index] [Thread Index] [Author Index]

Search the Archive

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]
]

because add1[a] will work but add1[1] won't. I have read that there were  
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  
discarded.

Maxim Rytin
m.r at inbox.ru


  • Prev by Date: Re: InitializationCell -> Toggle shortcut key
  • Next by Date: Re: Plot axis numbers
  • Previous by thread: Re: letrec/named let
  • Next by thread: Re: letrec/named let