Arc Forumnew | comments | leaders | submitlogin
1 point by Pauan 5128 days ago | link | parent

Hm... why wouldn't something like this work?

  (let old fn
    (mac fn (names . body)
      (w/uniq a
        `(,old ,a
           (let ,names nil
             (= ',names ,a)
             ,@body)))))


  (fn args (+ 1 5))  -> (<fexpr fn> gs524
                          (let args nil
                            (= 'args gs524)
                            (+ 1 5)))
    
    
  (fn (n x) (+ n x)) -> (<fexpr fn> gs525
                          (let (n x) nil
                            (= '(n x) gs525)
                            (+ n x)))
Remember: the destructuring/optional/rest/etc. functionality would only be when the first argument to `=` is quoted.

Derp, I just realized that `let` desugars to `fn`, which doesn't have destructuring. I guess you could replace `let` with `with` and it would still work, albeit it would be clunkier. Something like this:

  (let old fn
    (mac fn (names . body)
      (w/uniq a
        `(,old ,a
           (with ,(if (isa names 'cons)
                        (mappend [list _ nil] names)
                      (list names nil))
             (= ',names ,a)
             ,@body)))))
You could also optimize it, so it expands into a normal `fn` when the argument list is a symbol, like (fn args) but does the special stuff when it's a cons, like (fn (a b)):

  (let old fn
    (mac fn (names . body)
      (if (isa names 'cons)
            (w/uniq a
              `(,old ,a
                 (with ,(mappend [list _ nil] names)
                   (= ',names ,a)
                   ,@body)))
          `(,old ,names ,@body))))
The above does expand properly in Arc 3.1... except you need to replace (let old fn with (let old 'old-fn because Arc doesn't have first-class special forms like PyArc. :P


1 point by rocketnia 5128 days ago | link

Yeah, 'fn is the most basic way to make local variables in pg-Arc, and everything else is based on that. The problem I see with basing 'fn on a simpler, non-destructuring version of 'fn, 'with, or 'let is that somehow you need to take things like (a (b c) d=1 e=2) and extract their variables for use in the simpler form. Otherwise you get cases like this:

  (simple-fn gs525
    (simple-let-nil (a (b c) d=1 e=2)
      (= '(a (b c) d=1 e=2) gs525)
      ...))
By the time you to all the trouble to make this 'simple-let-nil work, you might as well have made 'fn with destructuring built in.

...Well, since you're in an interpreter, you may be able to get away with this:

  (simple-let gs1 (argument-list-vars '(a (b c) d=1 e=2))
    (simple-fn gs2
      (interpreted-simple-let-nil gs1
        (= '(a (b c) d=1 e=2) gs2)
        ...)))
There are probably plenty of other possibilities I'm overlooking too. ^_^

Oh, and I suppose my Penknife plan is another option. The core language could supply a simple 'fn, and another namespace could supply a more advanced 'fn once enough functionality has been built up based on the core.

-----

1 point by Pauan 5128 days ago | link

Hm... yeah, that makes sense. Alrighty then, let's try to get `=` to desugar to a function, so we can get destructuring assignments. :P I figure (= '(a b) nil) could desugar to this:

  (with (gs204 nil gs205 nil)
    (= a gs204)
    (= b gs205))
And then (= '(a b (c d)) '(1 2 (3 4))) could desugar to this:

  (with (gs206 1
         gs207 2
         gs208 (3 4))
    (= a gs206)
    (= b gs207)
    (= c gs208))
Hm... but that wouldn't work recursively, so it would only be one level of destructuring. In which case you might as well use something simpler:

  (do
    (assign a 1)
    (assign b 2))

-----

1 point by rocketnia 5127 days ago | link

It sounds like you're ending up with the same thing as setforms. That'll at least work, but it's not what I thought you meant by having '= desugar to a function.

I thought you meant something like this:

  (= '(a b (c d)) '(1 2 (3 4)))
  -->
  (apply (fn (a b (c d))
           (export-locals-to-parent-scope))
         '(1 2 (3 4)))
And come to think of it, that's something which might actually make sense in an interpreter.

The setforms way is what I'd choose, at any rate. ^_^

-----

1 point by Pauan 5127 days ago | link

That would work, yes, but it'd require adding an `export-locals-to-parent-scope` built-in (or similar), as you say. Preferably, I'd like to define it in a way that's compatible with pg-Arc.

It's not a big deal, though. In a worst-case scenario, we can define `=` so it does a single level of destructuring. That should be simple to add, even in pg-Arc, while still providing some usefulness.

P.S. `with` expands to a function, so technically it is desugaring to a function. :P Your idea is quite a bit shorter and simpler, though.

Also... this just reminded me of something: lambdas in JavaScript. If I recall, there was a proposal for "thin" functions in JS, which (among other things) would not have "var" scope:

  function foo() {
    (lambda {
      var bar = 10;
    })()

    return bar;
  }

  foo() -> 10
Basically, any "var" statements would act as if the lambda wasn't even there, thus assigning them to the outer scope. After looking it up, it seems that "lambda" was changed to "#", which is quite a bit shorter (http://brendaneich.com/2011/01/harmony-of-my-dreams/).

A similar "thin-fn" form in Arc might be an interesting experiment: any assignments within the thin-fn would always assign to the outer scope. You could still assign locally, by using `let`, since that desugars to a "heavy" function:

  (def foo (a)
    ((thin-fn (a)
      (= a "foo")))
    a)
      
  (foo) -> "foo"
        
        
  (def foo (a)
    ((thin-fn (a)
      (let a nil
        (= a "foo"))))
    a)
        
  (foo) -> nil
Then we could have `=` desugar to a thin-fn, which would work without needing an `export-locals-to-parent-scope` built-in. The advantage of this approach is that it's more general: other functions might be able to make use of thin-fn's too.

...but, Arc fn's already behave like the lambda proposal for JS, so the problems that JS is trying to solve simply don't exist in Arc. Thus, it's arguable whether Arc should have "even thinner" fn's or not.

-----