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.
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:
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. ^_^
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.