Arc Forumnew | comments | leaders | submitlogin
Self referencing lambda
1 point by lojic 6170 days ago | 9 comments
While experimenting, I thought I'd take the definition of foldl from SICP and implement it in Arc. My first draft was:

  (def foldl (op initial sequence)
    (def iter (result rest)
      (if (no rest)
        result
        (iter (op result (car rest))
              (cdr rest))))
    (iter initial sequence))
  
  arc> (foldl + 1 '(2 3 4))
  10
but that redefines iter each time. What is the proper way to do this in Arc while keeping the structure of the original? I know I can just use a recursive function and pass the op, but the point is to create a self-referencing lambda in Arc.


1 point by kennytilton 6170 days ago | link

btw, here is while (from arc.arc):

(mac while (test . body) (w/uniq (gf gp) `((rfn ,gf (,gp) (when ,gp ,@body (,gf ,test))) ,test)))

-----

1 point by kennytilton 6170 days ago | link

You want rfn, the equivalent of CL labels as far as I can make. So /I think/ the above should just be (rfn iter...) instead of (def iter...).

-----

1 point by lojic 6170 days ago | link

Thanks. Here's a version with afn after I got help on #arc:

  (def foldl (op initial sequence)
    (let iter (afn (result rest)
                (if (no rest)
                  result
                  (self (op result (car rest)) 
                        (cdr rest))))
      (iter initial sequence)))
but it uses self inside the lambda and iter outside. I'll look into rfn.

-----

2 points by simonb 6170 days ago | link

I don't think rfn will help here. rfn is useful for macros to prevent shadowing self and perhaps some obscure tricks involving mutually recursive nested lambdas.

However in your case you can get rid of let with a simple function call:

  (def foldl (op initial sequence)
    ((afn (result rest)
        (if rest
          (self (op result (car rest)) (cdr rest))
          result))
     initial sequence))

-----

1 point by lojic 6169 days ago | link

Of course - I do that in JavaScript all the time. Thx for the tip. Of course, I still want to be able to define a lambda that is bound to a name that also calls itself by the name instead of using self within and the name outside.

-----

2 points by simonb 6169 days ago | link

I think that's one of the cases where CL labels form would be more elegant.

But luckily this is Lisp so it shouldn't be too hard to make with a wee bit smarter so it would transform

  (with (foo (fn ...)))
to

  (with (foo (rfn foo ...)))

-----

2 points by randallsquared 6170 days ago | link

Ah, so rfn is short for 'recursive fn'.

-----

2 points by kennytilton 6170 days ago | link

Looks that way. :) This is why I think arc.arc should look like: (mac rfn yadda yada "Recursive FN: an anonymous function that can call itself" ...implementation...) FYI, CL is funny, both flet and labels elt us give names to loacl functions, but only those declared with labels can be called recursively. I wonder why flet got kept, backwards compatibility?

-----

2 points by randallsquared 6170 days ago | link

Well, as you know, there's a LOT of that in CL. CL is the PHP of lisps. :)

-----