I'm a little unclear as to what @ really does. What is the reason you want @? Is it just for let statements, or for any statement? Is it to make cleaner code, or for efficiency? Can you post some code that you think works better or is more elegantly written using @, rather than without it? Maybe some code of 5-10 lines?
I've actually wanted something similar from time to time, but without the '@ and 'let. Right now, I have just one place I really miss it (which you can see at http://github.com/rocketnia/lathe/blob/c343b0/arc/utils.arc), and that place currently looks like this:
(=fn my.deglobalize-var (var)
(zap expand var)
(if anormalsym.var
var
; else recognize anything of the form (global 'the-var)
(withs (require [unless _
(err:+ "An unrecognized kind of name was "
"passed to 'deglobalize-var.")]
nil (do.require (caris var 'global))
cdr-var cdr.var
nil (do.require single.cdr-var)
cadr-var car.cdr-var
nil (do.require (caris cadr-var 'quote))
cdadr-var cdr.cadr-var
nil (do.require single.cdadr-var)
cadadr-var car.cdadr-var
nil (do.require anormalsym.cadadr-var))
cadadr-var)
))
(Note that the Lathe library defines 'anormalsym to mean [and _ (isa _ 'sym) (~ssyntax _)]. Also, 'my is a Lathe namespace here, and I use Lathe's straightforward '=fn and '=mc to define things in namespaces. Finally, don't forget that (withs (nil 2) ...) binds no variables at all ('cause it destructures).)
If I define something like 'scope, I save myself a few parentheses and nils:
(=mc my.scope body
(withs (rev-bindings nil
final nil
acc [push _ rev-bindings])
(while body
(let var pop.body
(if no.body
(= final var)
anormalsym.var
(do do.acc.var (do.acc pop.body))
(do do.acc.nil do.acc.var))))
`(withs ,rev.rev-bindings ,final)))
(=fn my.deglobalize-var (var)
(zap expand var)
(if anormalsym.var
var
; else recognize anything of the form (global 'the-var)
(my:scope
require [unless _
(err:+ "An unrecognized kind of name was passed "
"to 'deglobalize-var.")]
(do.require (caris var 'global))
cdr-var cdr.var
(do.require single.cdr-var)
cadr-var car.cdr-var
(do.require (caris cadr-var 'quote))
cdadr-var cdr.cadr-var
(do.require single.cdadr-var)
cadadr-var car.cdadr-var
(do.require anormalsym.cadadr-var)
cadadr-var)
))
Furthermore, I suspect this version of 'scope would almost always be preferable to 'do, 'let, and 'withs, partly because it's easier to refactor between those various cases. However, it doesn't do any destructuring, and it's probably a lot harder to pretty-print. (I'm not even sure how I would want to indent it in the long term.)
That example doesn't really call out to me: it looks like you could save yourself a few parentheses and nils by refactoring with something simpler, rather than with a complex macro. E.g., if I understand the code correctly:
(=fn my.aglobal (var)
(and (caris var 'global)
(single:cdr var)
(caris var.1 'quote)
(single:cdr var.1)
(anormalsym var.1.1)))
(=fn my.deglobalize-var (var)
(zap expand var)
(if (anormalsym var)
var
(aglobal var)
var.1.1
(err "An unrecognized kind of name was passed to 'deglobalize-var.")))
But then, I avoid setting variables in sequence like that.
Hmm, I kinda prefer local variables over common subexpressions. It's apparently not for refactoring's sake, since I just name the variables after the way they're calculated, so it must just be a premature optimization thing. :-p
But yeah, that particular example has a few ways it can be improved. Here's what I'm thinking:
(=fn my.deglobalize-var (var)
(zap expand var)
(or (when anormalsym.var var)
(errsafe:let (global (quot inner-var . qs) . gs) var
(and (is global 'global)
(is quot 'quote)
no.qs
no.gs
anormalsym.inner-var
inner-var))
(err:+ "An unrecognized kind of name was passed to "
"'deglobalize-var.")))
I still like 'scope, but I'm fresh out of significant uses for it.
(To continue the digression into this particular case...) I had thought about destructuring, but found the need for qs and gs ugly. Really, a pattern matching library would be opportune. But since there's no such luck in Arc proper, it'd be ad-hoc and probably altogether not worth it (though not difficult to implement). I say this with respect to vanilla Arc; I don't know if Anarki has such a library. Still, it'd be hard to beat something like
(=fn my.deglobalize-var (var)
(zap expand var)
(or (check var anormalsym)
(when-match (global (quote ?inner-var)) var
(check ?inner-var anormalsym))
(err "An unrecognized kind of name was passed to 'deglobalize-var.")))