Arc Forumnew | comments | leaders | submitlogin
Local recursive functions
2 points by guynoir 5323 days ago | 3 comments
Am still browsing the Arc source attempting to find this, but maybe some kind knowledgeable person can answer this: is there anything like LABELS from Common Lisp in Arc? That is, a facility allowing for the named local recursive functions. One could use the Y combinator instead, but the still I feel a need for such a facility.


4 points by rocketnia 5322 days ago | link

You could do a couple of things.

If it's just one self-recursive function, use 'afn or 'rfn:

  (let factorial (afn (x)
                   (if (is x 0)  0
                       (< 0 x)   (self:- x 1)))
    factorial.12)
  
  (let factorial (rfn custom-name (x)
                   (if (is x 0)  0
                       (< 0 x)   (custom-name:- x 1)))
    factorial.12)
(Note that 'afn is just 'rfn with the name 'self already chosen for you.)

If one local function just needs to refer to another, you can use 'withs:

  (withs (get-street [...]
          format-address [... get-street._ ...])
    ...)
I doubt that's what you're looking for though, 'cause it's just a convenience for doing this:

  (let get-street [...]
    (let format-address [... get-street._ ...]
      ...))
If it's two or more actually corecursive functions you need, you can use a manual letrec pattern. (Is CL's 'labels basically the same as Scheme's 'letrec?)

  (let (odd even) nil     ; destructuring, so both start as nil
    (= odd [case _ 0 nil (even:- _ 1)])
    (= even [case _ 0 t (odd:- _ 1)])
    odd.12)
In fact, if you're using Anarki (http://github.com/nex3/arc), this kind of letrec is already defined as 'withr:

  (withr (odd [case _ 0 nil (even:- _ 1)]
          even [case _ 0 t (odd:- _ 1)])
    odd.12)
...I really like reducing parentheses though, so just now I added my own 'letrec to Lathe (http://github.com/rocketnia/lathe). :-p

  (use-rels-as ut (+ lathe-dir* "utils.arc"))
  
  ; The bindings all have to be everyday variable names, but this
  ; detects them automatically. You can use with-style parentheses too,
  ; in case you need to be extra sure.
  (ut:letrec odd [case _ 0 nil (even:- _ 1)]
             even [case _ 0 t (odd:- _ 1)]
    odd.12)

-----

1 point by evanrmurphy 5322 days ago | link

Hi guynoir. (Garrison Keillor fan? :) Maybe you're looking for rfn, which is defined as follows in arc.arc:

  (mac rfn (name parms . body)
    `(let ,name nil
       (assign ,name (fn ,parms ,@body))))
Here's a trivial example:

  ; prints 1..10, each on its own line

  ((rfn foo (x)
    (prn x)
    (if (>= x 10)
         nil
        (foo (+ x 1))))
  1)
Hope this helps.

-----

1 point by guynoir 5322 days ago | link

Thanks a lot for the illuminating replies guys.

@rocketnia: Will also try the additional versions/libraries that you indicate, much appreciated---am quite new to the Arc world.

@evanrmurphy: Thanks and yes, I am a GK fan :-)

-----