Cool! I wanna be like Paul Graham; someone buys some Lisp thing I made. :)
>
>> > or maybe:
>> >
>> > (loop #:for x #:in '(1 2 3) #:collect ...)
>> >
>> > The cost of that extra syntax is not just the cost of typing in #:all
>> > #:that #:extra #:punctuation.
>>
>> Yes; "colon-free" loop is way easier to "sell" to non-Lisp programmers.
>
> That is a significant win by my personal quality metric.
Me too.
>> The keyword punctuation is not very helfpul in Loop because you're not
>> manipulating property lists or keywords.
>
> Not sure what you mean by "manipulating keywords" but you're probably
> right.
Like suppose that the data type being manipulated in loop is mostly keywords,
and all the clause words are keywords too.
(loop :for x :in '(:for :and :with)
:for y = :collecting then x
:if (eq x :and)
...)
Not sure where I'm going with this so I will stop. :)
That looks like it has the measles.
>> The punctuation on keywords is quite helpful in argument or property lists,
>> especially long ones. It says "this is the indicator, and the thing to the
>> right must be the property".
>
> Yes. But that still leaves open the question of whether or not this
> helpful feature should be baked into the design of the language, or
> whether it should be, for example, a programming convention like
> *earmuffs*.
But *earmuffs* is pretty much baked into the language.
>
> The Right Syntax for indicating indicators, the one that would conform
> to the syntactic conventions of natural language (at least European
> languages) is to put the colon at the END of the word, not the
> beginning. Dylan and Objective C get this right.
Well, objectionable C also:
repeat:
goto repeat;
:)
> because it tried to shoehorn keyword syntax into the syntax of symbols,
> where the natural interpretation of foo: would be 'foo::|| rather than
> the desired '||::foo (or keyword::foo).
>
> All of these issues simply evaporate if you add one level of indirection.
>
>> One of the things I found confusing as a Lisp newbie was
>> :initarg :blah :initform foo in defclass. When the argument of a keyword is
>> :a
>> keyword, the colons no longer help. No it was before Lisp newbie time; I
>> think
>> I saw that first in that OO book by Grady Booch and went "gack".
>>
>> If you drop the colon, everything will be screwy like that.
>>
>> A modicum of "sygils" can improve readability.
>
> Agreed. But to reiterate, the issue is not whether sigils are useful,
> but rather whether the syntax for them should be unalterably baked into
> the specification of the language. In a "programmable programming
> language" like CL I believe the design principle should be that you
> ought not bake things into the language unless there's a compelling
> reason.
A broad rule for a class of symbols that they evaluate to themselves is
pretty cool. nil and t ought to have been keywords, :nil and :t.
>> >> But for keyword tokens to be "non clunky" (identifiers with zero
>> >> characters
>> >> of
>> >> additional syntax) maybe other things in the language would become clunky,
>> >> possibly such that the overall clunkiness increases.
>> >
>> > Only if you do it wrong. It is a pretty minor tweak to CL's current
>> > design to have the best of both worlds. All you need to do is to add a
>> > level of indirection. Instead of:
>> >
>> > string->(reader)->symbol
>> >
>> > do:
>> >
>> > string->(reader)->keyword->(lexicon)->symbol (or whatever)
>>
>> So everything coming out of the reader is a keyword.
>
> In a perfect world, yes.
>
>> I'm trying to form a picture of how that would work.
>
>
http://flownet.com/ron/lisp/lexicons.pdf
>
http://flownet.com/ron/lisp/lexicons.lisp
Is this new in the latest version or just from old behavior?
>> Keywords connect remote parts of a program together so they can't be tied to
>> lexical scopes. Or can they?
>
> Not sure what you mean by this. Symbol name collisions are inherently a
> dynamic phenomenon.
I just mean that they are part of the expression of interfaces.
> That's one of the coolest thinks about lexical scopes: they naturally
> form a hierarchical structure so that there is an obvious rule for
> resolving name conflicts. Indeed it is so obvious that people don't
> even THINK of lexical name conflicts as conflicts. The rule is: inner
> scopes shadow outer scopes. That rule turns out to be all you need.
That rule is error-prone. That's why we have a -Wshadow gcc warning.
Good for machines though.
>> If some function f has a keyword argument x, and we don't have special
>> keywords
>> in the language, we have to pass that as 'x. To get rid of the quote, we can
>> use our lexicon to bind x to 'x. That is inconvenient.
>
> I don't see why 'x is any more inconvenient than :x.
Well, I'm now drinking the "sygil is bad" Kool-Aid for a moment. So if I throw
away :, but gain ', I have not achieved anything.
> I completely agree that (f 'keyword value) is unaesthetic. It should be
> (f keyword: value). But the way CL is currently defined, that is
> necessarily a syntax error unless you muck with the reader to make #\: a
> constituent, but that carries a steep price, namely, the loss of
> read-print consistency.
Me, I don't care if it goes to the front or back. I'm AC/DC.
> The Right Way (IMO of course) is for #\: to be a constituent, and for
> the reader to produce keywords, which should be a distinct data type
> from symbols. Keywords should be (isomorphic to) immutable strings.
Yes, so then they can be interned similarly to symbols (and used for low loopy
things).
> The names of symbols should be keywords (i.e. immutable strings), not
> (mutable) strings.
Interesting. So (name-equal x y) reduces to (eq (symbol-name x) (symbol-name y)).
> The leaf nodes of programs should be keywords, not
> symbols. The semantics of programs made of keywords are mapped onto the
> semantics of programs made of symbols by adding a pass that maps
> keywords onto their corresponding bindings in the current lexicon, which
If keywords have bindings they are symbols, which we said they are not. :)
Basically they might as well be symbols, but in a special category.
Shit, actually I had nearly the same idea several days ago. The idea
was that there should be symbols which are not in any package.
And that symbols should be separately interned in a package
and in the "no package" zone.
> is a first class lexical environment that maps keywords onto symbols --
> or possibly other things. (There are benefits from having lexicons map
> keywords onto things other than symbols, but let's deal with one thing
> at a time.)
>
> (Actually, I skipped a step here. The semantics of programs made of
> keywords are defined relative to a first-class global environment object
> that maps keywords onto some kind of value(s). That does not
> necessarily have to be a lexical environment. It can be a dynamic one.
> That's what e.g. Python does. Making it a lexical environment has, I
> believe, certain benefits. But the real point here is not so much that
> the global environment is lexical as that it is first-class.)
>
>> But could have a rule so that if x has no binding in the enclosing stack of
>> lexicons, then x just evaluates to x. But what about catching uses of unbound
>> variables.
>
> I would handle this with reader macros. If you wanted CL-style keyword,
> just define a reader macro on #\: that reads :foo as (quote foo).
But then '(:foo bar) is (quote ((quote foo) bar)). No thanks! I want :foo
to be the same thing whether it is code or data.
(This is a little bit like (define nil '()) in Scheme. It fails to
make '(nil) a list of an empty list.)
A macro that gives me a : spelling for ' is not that productive.
> You have to get a little fancier to be able to implement my preferred
> syntax of foo: , but as I said, one thing at a time.
>> Maybe that's okay; it will just blow up in a different place: a symbol ends
>> up passed where some type of other value is expected.
>>
>> (let ((misspelled 'foo)) (symbol-name misspeled)) gives
>> you "MISSPELED" instead of "FOO", with no help from the compiler, but
>> that seems minor.
>
> The reason you can't create lexical bindings for keywords in CL is NOT
> that it would lead to naming conflicts. It's because keywords are a
> special kind of symbol. They are special (no pun intended) because
> every keyword is implicitly defined to be a constant bound to itself,
> and you can't rebind constants.
Yes, which is great.
> But imagine if instead of being bound by DEFCONSTANT, keywords were
> instead bound by DEFPARAMETER. Then you could do, e.g.:
>
> (let ((:x 1)) :x) --> 1
>
> Yes, I know, you look at that and think Blech! That would break all
> kinds of things, and you're right, it would.
No it wouldn't because nobody does that today. But the problem is that
:x is still just :x outside of that lexical scope. And pieces of data
in that lexical scope are outside of that lexical scope:
:x may produce 1, but (car '(:x)) doesn't.
> NOT break is that it would not cause symbol naming conflicts.
>
> So now imagine a hypothetical lisp that differs from CL in the following
> respects:
>
> 1. The reader produces keywords by default
> 2. The names of lexical bindings are keywords, not symbols
> 3. There is a reader macro on #\: that reads :x as (quote x), which is
> a list of two elements, both of which are keywords.
> 4. EVAL is just like the usual Lisp 1.5 eval, except that the ENV
> argument uses keywords for keys rather than symbols. In the default
> environment, the keyword QUOTE is bound to a fexpr of one argument that
> returns that argument.
>
> In such a Lisp you could write:
>
> (let ((x 1)) (f :x x))
>
> and it would do exactly the same thing as that code does in CL. And the
> result from your example above would be "FOO" just as you expect.
>
> Are you with me so far?
I think it might be better like this:
1. The reader produces keywords by default
2. Keyword are interned in a global table (like a package,
but it's only for keywords and there is only one).
So if a keyword X escapes from one lexical scope and
travels into another, it is the same object as the X
occuring in that lexical scope.
2. The names of lexical bindings are keywords, not symbols
3. If a keyword is evaluated which has no apparent lexical
binding, this is not a free reference. Rather, the value
is that symbol itself. So it is not necessary to quote
keywords: anything you don't bind is a keyword.
4. Programmers who want to distinguish never-bound keywords
from usually-bound keywords can use a convention
analogous to *earmuffs* for CL specials. That convention
can be foo: for Europeans, RG and :foo for sane people.
The colon is just a constituent. So if there is no
binding for :foo, then (eq :foo (car '(:foo))).
4. EVAL is just like the usual Lisp 1.5 eval, except that
the ENV argument uses keywords for keys rather than
symbols. In the default environment, the keyword QUOTE
is bound to a f***r of one argument that
returns that argument.
[Please *** out dirty words; there are children reading.]
I don't see how dynamic bindings fit into this and also regular symbols which
are not keywords. Also, hygiene in macros?