3 ms·
Consider this snippet of C code: struct foo { int x; } Do you care how the structure definition is represented in your compiler? is it a list,
by junke 10y ago
Consider this snippet of C code:
struct foo {
int x;
}
Do you care how the structure definition is represented in your
compiler? is it a list, a vector or a custom data-structure? You don't
know, and it doens not matter to you. Besides, it is totally different
from what you manipulate at runtime (for type definitions, not
much). Consider the second snippet:
for(int i = 0; i < n; ++i) {
// something
}
Should the internal representation for the block delimited by braces
be necessary the same as the one used to represent the fields in the
previous structure? I mean, do the brace characters always map to the
same internal data-structure? Probably not. In C, the concrete syntax
has generally nothing to do with the abstract syntax. This is not the
case in Lisp, because each syntax is used to parse a specific type of
data.
In Clojure, you write #{...} and the reader (LispReader.java) sees the
sharpsign followed by brace and builds a set containing the values
inside the braces. That set is contained inside the AST, and acts as a
literal value. That value is shared among all invocations of your
code, meaning that if you call the enclosing function at different
places, the same literal object is shared. Since this data is
immutable, this is not really a problem because when you add more
elements at runtime, the original literal is not modified. OTOH, you
can still invoke EvalReader, #=(), which evaluates code at
read-time. I believe that you can put mutable data-structures into the
AST and obtain funny results by mutating it during execution.
How is it different from Common Lisp? Not much.
Common Lisp is less restrictive because the readtable can be
customized. Also, the standard data-structures are mutable (however,
the behavior is undefined if you try to mutate literal data; some
compilers warn you about that). I don't think I ever needed to have
hash-table as a literal, it seems practically useless because if you
want a hash-table in your source code, odds are that it contains few
elements. If so, an association list is simpler (and more efficient).
If you really really need a complex data-structure in your source
code, you are more likely to use LOAD-TIME-VALUE anyway, because it
works better with a compiler: not all data-structures are (nor should
be) automatically serialisable in the object file (they could containt
transient data, for example). In other words, your original code has
little to do with the machine code that is produced and eventually
loaded (possibly in another environment). LOAD-TIME-VALUE is a way to
execute code at load-time to produce such data-structures in your
code: I have a parser which pre-computes some regexes, and this is not
something that has an equivalent in Clojure, as far as I know.
So my first point is: you can have literals of any type in your source
code in Common Lisp (like in Clojure). All of them have dedicated
syntax, like vectors of arbitrary dimensions #2A((1 2)(3 4)), bit
vectors #*1111, complex numbers #C(0 1), pathnames #P"/tmp/foo", and
of course strings. Likewise, you have a generic syntax for
structures. Suppose you define a structure FOO with a single slot X,
then #S(foo :x 10) is a literal of that type.
However, not all data-structures have such syntax: maybe it was not
deemed necessary to represent literal hash-tables in source code, or
maybe it did not make it to the standard, I don't know. I personally
don't miss it and I am happy to use auto-complete the few times I need
a hash-table. However, if you want you can customize your Lisp easily;
for example, load the FSET library and provide a custom syntax over
immutable data-structures. If you look at Maxima, it has a lot of
custom syntax. And I am not talking about macros, but about changing
the readtable which reads Lisp objects from a stream. An example of
this is RUTILS[0], which provides the #h(equal "k1" v1 "k2" v2) syntax
for hash-table. But note that this notation is only used to produce a list,
namely the code required to produce a hash-table at runtime and
populate it.
Which brings me to my second point: there is a big difference with
Clojure in that Common Lisp doesn't use different types to provide
syntactic sugar. For example, in Clojure [] is for vectors, {} is for
maps and #{} is for sets. That literally means that when you have a
binding, you allocate a vector. When you destructure a map with
map-notation, you use internally a map. So the language is mixing two
concepts: syntactic sugar and actual internal representation. I find
this rather hackish but I can live with it because it probably has
little incidence. I think it adds complexity to the compiler which has
to walk different kinds of code. Besides, the usage of such syntax is
not regular: sometimes vectors are for unevaluated data, sometimes for
bindings or destructuring, so you still need context to know what you are
doing. Those are minor points, and I understand that Clojure can look more convenient to use. However Common Lisp being a little more wordy is not a problem for me.
[0] http://lisp-univ-etc.blogspot.fr/2016/05/improving-lisp-ux-one-form-at-time.html http://lisp-univ-etc.blogspot.fr/2016/05/improving-lisp-ux-o...
- keymone 10y agoyou're talking from the perspective of an experienced lisper. i'm talking from perspective of somebody that wasn't convinced by CL but was later convinced by Clojure. that is the whole point of the thread - why hasn't lisp caught on, and i'm an example of both failure and success in that regard. i mostly agree with all you've said, just few comments: > I think it adds complexity to the compiler which has to walk different kinds of code. either you deal with complexity or your users will have to. it's not always clear where the boundary should be though i like where clojure puts it. > I understand that Clojure can look more convenient to use. However Common Lisp being a little more wordy is not a problem for me. s/me/experienced commonlisper/ aaand that's the whole point.
- junke 10y ago> you're talking from the perspective of an experienced lisper. If I am an experienced Common Lisper, it is because I was once a noob Common Lisper and already not bothered by syntax. Maybe that's because I already had experience with several other languages, which have all some superficial negative aspects. That being said, I prefer to use CL but I don't mind using Clojure. > either you deal with complexity or your users will have to. I did not say the complexity was necessary present in one case or another. Biased as I am, I see no complexity with a simple, regular usage of parenthesis. Brackets and braces are good in the eye of other kind of people, sure. > that is the whole point of the thread - why hasn't lisp caught on, and i'm an example of both failure and success in that regard. Well, should we generalize from your example then, when it is not appropriate to do so in my case? Besides, I was mostly responding to your posts about literal values.
- keymone 10y ago> Biased as I am, I see no complexity with a simple, regular usage of parenthesis. > If I am an experienced Common Lisper, it is because I was once a noob Common Lisper > should we generalize from your example then, when it is not appropriate to do so in my case if we do so carefully? obviously there is some spectrum of how mentally exhausting various aspects of language's syntax are for people, and how prepared/willing different people are to wrap their heads around those aspects. crude analogy would be saying unary number system is better than decimal because it's simpler (via having less "things"), all operations are more intuitive and there is no complexity in dealing with all those digits. just as we use decimal instead because we have physiological reasons to do so, it's not outlandish to suppose that we have psychological reasons to prefer syntax that is more rich than what CL provides out of the box but also not too rich because it's mentally exhausting. clojure seems to be hitting the sweet spot(at least within lisps family) and while many factors are at work here, the evidence is that clojure quickly became more popular than cl. to be clear, i'm not saying here that popular = better, of course.