6 ms·
> Everything is either list or atom and almost everything is atom. how can you both say this and that i'm talking out of ignorance? you're basically confirming
by keymone 10y ago
> Everything is either list or atom and almost everything is atom.
how can you both say this and that i'm talking out of ignorance? you're basically confirming my words.
larger point i was making is that "everything is a list" abstraction/metaphor influenced the decision to not include native representation of other data structures into the language. because parens are enough to represent everything. well they aren't enough for people looking for convenient, practical and simple languages.
- Grue3 10y agoNo, you're wrong. Common Lisp has hash-tables, arrays and pretty much any data structure you need. But they are not lists, they are atoms. Hence why almost everything is an atom. It's well known that linked lists are inefficient in many ways. Nobody writes programs using only lists.
- keymone 10y agoabsence of data literals. i'm not sure how can i state it clearer.
- DonaldFisk 10y agoAtoms in Lisp aren't what you think they are. All data structures except dotted pairs (from which lists are made) are atoms. For example, arrays and hash tables are atoms.
- nabla9 10y agoIt's the Lisp nomenclature that confuses you. In list everything is either atom or a list. `atom` type is equivalent to `(not cons)`. CL has plenty of native data structures including hash tables, streams, files, functions, arrays, strings, numbers, characters, structures, ... http://clhs.lisp.se/Front/Contents.htm http://clhs.lisp.se/Front/Contents.htm
- keymone 10y agohaving functions to manipulate some data structures doesn't mean it's native to language. by that standard everything is native everywhere. lisp stretches the meaning of "native" by power of macros, but something being possible still doesn't make it practical or convenient.
- junke 10y agoConsider 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...