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