Arc Forumnew | comments | leaders | submitlogin
Mutual recursive lambdas in a with?
5 points by ambition 5975 days ago | 7 comments
With afn, I can make a recursive unnamed function by calling (self) in the body of the function.

This lets me do:

    (with (my-func (afn (a1 a2) (... (self ...) ) )
          something else...)
          ...code using my-func...)
I'm sure there is a simple answer, but what if I want the equivalent of:

    (with (my-func1 (fn (x y) (my-func2 ... ))
           my-func2 (fn (a b) (my-func1 ... )))
           ... code... )


7 points by tokipin 5974 days ago | link

"withs" is the recursive binding thingie but in this case let is nicer:

  (let (f1 f2) nil
    (def f1 () (prn "bob") (f2))
    (def f2 () (prn "bib") (f1))
  
    (f1))
using withs, i couldn't bind a variable twice in the same declaration so it ended up being ugly:

  (withs (f2 nil
          f1 (fn () (prn "bob") (f2)))

         (def f2 () (prn "bib") (f1)) ; f2 can't be bound again in the withs part, maybe a bug
  
      (f1))

-----

2 points by skenney26 5974 days ago | link

(With very minimal testing)

  (mac mrec (fns . body)
   `(let (,@(map1 car fns)) nil
      ,@(map1 (fn (f) `(def ,@f))
              fns)
      ,@body))

  arc> (mrec ((f1 () (prn "bob") (f2))
              (f2 () (prn "bib") (f1)))
         (f1))
  bob
  bib
  bob
  bib
  ...

-----

3 points by rntz 5973 days ago | link

This won't work if you want to define a function called 'o. Reason: (let var val ...) becomes ((fn (var) ...) val), and if var is (o ...), it becomes ((fn ((o ...)) ...) val). (o ...) is interpreted as an optional parameter, which disables destructuring.

Destructuring in lets is a nice idea, and using this with nil is a cool hack, but until and unless this behavior is changed, don't rely on it in macros - it can cause unexpected code breakage. A better way to do it would be the following (my 'fwithr is your 'mrec).

    (mac withr (bindings . body)
      (let bindings (pair bindings)
        `(with ,(mappend [list car._ nil] bindings)
           ,@(mapeach b bindings
               `(set ,@b))
           ,@body)))

    (mac fwithr (fns . body)
      `(withr
         ,(mappend [list car._ `(fn ,@cdr._)] fns)
         ,@body))
Edit: It seems almkglor has already done something like this, but his also has the "let doesn't always destructure" bug: http://arclanguage.org/item?id=7387

-----

1 point by ambition 5974 days ago | link

Oh, I see. I didn't do the 'f2 nil' line when trying withs so I got errors when f1 couldn't find f2. Also I didn't know you could do that with let!

Great help, thanks.

-----

2 points by drcode 5974 days ago | link

clever hack.

-----

2 points by tokipin 5974 days ago | link

just to make clear, i didn't come up with the autodestructured nil thing, despite having the good looks and intellect for it. credit goes to rkts:

http://news.ycombinator.com/item?id=265111

http://arclanguage.com/user?id=rkts

-----

3 points by almkglor 5974 days ago | link

http://arclanguage.org/item?id=7387

-----