You have a point, but let's distinguish between optional syntax (like : ' !) and mandatory syntax (as is used copiously in most languages)
Optional syntax has far fewer minuses, I would argue- New users wouldn't need to use it if they prefer not to.
Also, we're not talking about increasing syntax here, just using the existing syntax in a different way.
My personal thinking, though, is that it would be OK to go all out with the other special characters to generate optional syntax, as long as it is really, really, really well thought out. (other arc users, such as yourself, would probably disagree with this argument, however) Some special character for currying (such as described in the current arc.arc comments) would be a strong plus, I think.
the problem is that people will use it. i don't want to read through a:b.c code. my eyes are already optimized for (a (b c)) and i like it thank you very much.
What I really wanted to see was some method by which to determine if the caller specified an optional param, or didn't. I didn't want to depend on (o param 'some-random-value), because the user might actually want that value, and wrapping functions in w/uniq isn't exactly terse.
i have to most respectfully disagree friend. so far i like most everything i see in arc, but this ssyntax business does not resonate well with me. i thought it was only me (i'm getting old and all) but now i see some other people that are bothered by it so i feel i should say something. i think there is something to this.
I agree- using dots/exclamations in multiparameter functions is definitely pretty scuzzy, so it makes sense to use this semantic space for something else, too...
The reader (I would argue) should always make the assumption that the dot/excl implies single-parameter functions. This would be particularly nice in nested tables... Imagine we had a table of tables of city populations:
I think this idea has some merit. However, I would argue it's still not arcish enough (but better than other ideas I've seen)
The basic issue I would have with this is that variable capture like this happens maybe in 1/1000 uses of macros (thought it's already happened once to me, so I agree with your concern is valid)
However, your solution would make 100% of macro definitions ungainly, which is too high a cost, IMHO.
The best solution I can think of is:
1. Use your carat idea, except don't waste a valuable non-alpha character. Instead have a function "only-top" that guarantees that a symbol used as a function refers only to a toplevel definition (which would work through a shadowed name at the definition point, though the name would be a collision-safe gensym mapped to the toplevel definition via a hash table- not a carat appended name)
2. Give a warning when arc detects a name collision with a local variable during macroexpansion
*Warning- expansion of my-macro causes collision of symbol MY-FROB*
You could remove the warning (if you don't want to change the local variable name) by changing the macro to:
(mac my-macro (...) `(,(only-top 'my-frob) ...))
You would have some kind of similar method for hiding the error, in cases where the capture was actually desired.
With this solution, you could merily write macros without the cognitive load of an explicit name collision system, but still be safe from the problem when a rare name collision does occur.
"variable capture like this happens maybe in 1/1000 uses of macros (thought it's already happened once to me, so I agree with your concern is valid)"
How did it happen?! Did you skip a uniq out of laziness, or did the lexical environment into which you expanded rebind an Arc keyword or one of your own function names or ____? Maybe lisp-1 necessitates hygiene, and lisp-1 is The Real Problem.
As a longtime very relaxed CLer I must say I completely do not appreciate the naming paranoia I have experience with Arc/Lisp-1. Funcall is precisely what problem? My massive codebase shows 340 defmacros and 201 funcalls, which if you think about it is an astonishing ratio. (Think "define" vs. "invoke".)
> The basic issue I would have with this is that variable capture like this happens maybe in 1/1000 uses of macros (thought it's already happened once to me, so I agree with your concern is valid)
Have you written 1000 macros? If not I'd say you underestimate the odds. Also, whatever the odds are, they just get worse as the size of the code base increases.
> However, your solution would make 100% of macro definitions ungainly, which is too high a cost, IMHO.
But macros only make up a small percentage of typical code, so this might still be OK.
> The best solution I can think of is:
Two problems with this:
1. Issuing those warnings is not easy. It requires a code walker. If you're going to go to that much trouble you might as well implement real hygienic macros.
2. (only-top foo) seems even more ungainly to me than ^foo.
I personally don't think the ^foo idea is the perfect solution, but given that PG doesn't like hygiene or Lisp-2 it seems like a good alternative. Better than burying your head in the sand and hoping the problem doesn't happen IMHO.
There's just a problem: an error occurs on the macro user which must be fixed by the macro writer. Assuming the macro is complex enough, the user may not care to try hacking the macro source to get at the symbol to be (only-top ...)'ed.
Hmm. Problems, problems. My rename-the-local-variables solution won't work very well for macros which accept literal, unquoted symbols.
Understood, but if the user has the problem and doesn't want to hack on the macro, all they'd have to do is rename their local variable, which would be an OK comprise I think.
Here's a fully functional (as in, working) version of the ROBOTS game I wrote in CL that has heavy LOOP abuse (and FORMAT abuse). It would make a great arc exercise for someone :-)
BTW- Collisions of robots causes debris deadly to other robots.
-Conrad Barski
(defun robots ()
(loop named main
with directions = '((q . -65) (w . -64) (e . -63) (a . -1)
(d . 1) (z . 63) (x . 64) (c . 65))
for pos = 544
then (progn (format t "~%qwe/asd/zxc to move, (t)eleport, (l)eave:")
(let* ((c (read))
(d (assoc c directions)))
(cond (d (+ pos (cdr d)))
((eq 't c) (random 1024))
((eq 'l c) (return-from main 'bye))
(t pos))))
for monsters = (loop repeat 10
collect (random 1024))
then (loop for mpos in monsters
collect (if (> (count mpos monsters) 1)
mpos
(cdar (sort (loop for (k . d) in directions
for new-mpos = (+ mpos d)
collect (cons (+ (abs (- (mod new-mpos 64)
(mod pos 64)))
(abs (- (ash new-mpos -6)
(ash pos -6))))
new-mpos))
'<
:key #'car))))
when (loop for mpos in monsters
always (> (count mpos monsters) 1))
return 'player-wins
do (format t
"~%|~{~<|~%|~,65:;~A~>~}|"
(loop for p
below 1024
collect (cond ((member p monsters)
(cond ((= p pos) (return-from main 'player-loses))
((> (count p monsters) 1) #\#)
(t #\A)))
((= p pos)
#\@)
(t
#\ ))))))