The cons pair is a a really powerful primitive data structure, it is the linked list of Lisp. You can build a lot of powerful structures given this great base. I really don't it matters what architecture your running on.
Do they really confuse people new to Lisp? car+cdr is a pretty simple concept, when talking to new Lispers they usually don't complain about this.
Hash Tables are part of the Common Lisp Hyperspec so that is a non issue, they have been first class citizens since before Clojure existed (and are nicely integrated into things like loop)
I think their usage is sometimes a code smell (the ad-hoc structs I mentioned), but they're really useful when you want to deal with an "unlispy" list of tokens (say, a parser for a language that isn't Lisp).
>Hash Tables are part of the Common Lisp Hyperspec so that is a non issue, they have been first class citizens since before Clojure existed (and are nicely integrated into things like loop)
I'm not that familiar with Common Lisp, but a quick search didn't reveal a syntax for hash table literals, which I would consider to be a prerequisite for calling them first class citizens. There are other funny uses of lists (not improper ones, but still) in Common Lisp, like named procedure arguments[1]. I guess my point is, why encourage these weird constructs in the first place? Sexps are good at representing recursive structure, tables are good at mapping names to values, why not just have both and let them do what they're good at? Obviously Common Lisp is very old and can't be changed after the fact, I'm just trying to imagine the "ideal Lisp," whatever that is.
>Do they really confuse people new to Lisp? car+cdr is a pretty simple concept, when talking to new Lispers they usually don't complain about this.
I wasn't, but I've seen it confuse other people. Either way, it's a wart on the syntax that seems out of place in Scheme (not so in Common Lisp, which has lots of other warts ;))
>I come from a background using Common Lisp for system and web development so I may see things differently than people who were introduced to it academically.
Well, I was introduced to Scheme through SICP, but my motivation for picking it up was more practical than theoretical; I'd heard all the message board talk, Paul Graham essays, etc. proclaiming Lisp to be the most powerful, productive family of programming languages that will turn you into an expert programmer and so on, and wanted in on that ;) Maybe it's more practical to be Getting Shit Done™ instead of worrying about syntactic warts, but I think choosing to not have dotted pairs runs a bit deeper, by forcing the language to promote at least tables to a first class syntactic citizen.
[1] For the unfamiliar, it's something like:
(message "Text" :style bold :color red)
Reads pretty well, but it still seems wrong to me (ymmv), like it's another spot in the language begging for first class hash tables. In Lua, you'd emulate named arguments by passing a table to the function. I wonder what Clojure programmers do here. This? (message "Text" {style: bold, color: red})
Which doesn't make a big deal for readability, but I bet if you want to use a macro or whatever accepts named arguments, it'd be much easier to deal with the one with the real hash table.http://en.wikipedia.org/wiki/First-class_data_type
Hash-tables are part of the standard, and available in conforming implementations out-of-the-box. (make-hash-table) produces an instance of a table which can be passed as argument to function, be assigned to variables, ... I don't think syntax defines what feature is or isn't first-class, even though it has an impact on it's usage.
Adding support for litteral hash-tables is possible, as it was already said: define a reader macro; that macro could even simply use the utility function "plist-hash-table", from Alexandria, which is used like this:
(alexandria:plist-hash-table '(:a 1 :b 2))
So that you could write #H{:a 1 :b 2} and get what you want.On the first hand, people say that CL is bloated, but on the other hand, they want to have everything available by default. Do you expect Python or C++ implementations to come with regular expression built-in, or is it okay if you need to add an 'import' statement or link with Boost?
CL allows you to define libraries that can change even the basic surface syntax, for your convenience. Considering that there is more than enough defined in the specification, what benefits would be in having an "official" hash litteral syntax? consistency accross different projects? many people use the "cl-ppcre" regex library without problem.
Yes, regular expressions come in a library even though they could easily be labelled as a fundamental feature of a language, and hence be expected to be "first-class", or "built-in"; but again, that is not the case in CL, which is neither Perl nor Lua.
And about keyword parameters, this is just the surface syntax, which is on purpose based on a simple, basic representation of the syntax tree as lists of expressions.
Then, the compiler will work with the argument list in your function definition and take one or another approach to represent them in the object code. And I doubt that they are stored in a hash-table, which is unlikely an appropriate way to handle a couple of keyword arguments.
Similarly, when you define a class, everything is declared by a simple list of slots, where slots are lists of parameters: but in fact, the class might store the actual instance slots in a hash-table, an array, a list, a database or a memory mapped file.
The fact that you are mainly manipulating lists does not mean that everything is eventually represented as supposedly inefficient linked-list at runtime.
Fair enough, pretend I said "first class syntactic object."
> CL allows you to define libraries that can change even the basic surface syntax, for your convenience. Considering that there is more than enough defined in the specification, what benefits would be in having an "official" hash litteral syntax?
Reader macros are powerful, no doubt. The benefit of building this into a language would mainly be syntactic regularity. CL as it stands has keyword args, alists, property lists, and real hash tables (probably amongst other things I don't know about), that all fill basically the same purpose of mapping names to values. If the creators of Common Lisp and its parent lisps had started with hash tables with standard reader syntax, they probably wouldn't have felt the need to introduce so many subtly different but conceptually identical concepts. Lua, for instance, uses its single table data structure both as syntax and as an internal representation for pretty much any case where it needs to map some names to some values; from keyword arguments to environments to "metatables" that provide fairly powerful metaprogramming support, they're all just tables that you can write literally and use the same functions to manipulate. You could say that alists fill this purpose and are even more syntactically regular since they're still sexps, but then why doesn't CL use alists for keyword args, and why don't Scheme's keyword arg extensions use alist syntax? Historical accident, or are alists just ugly? If you can admit that they're a little too ugly and verbose to include in function calls, then maybe you can see why I don't like writing alist literals.
> The fact that you are mainly manipulating lists does not mean that everything is eventually represented as supposedly inefficient linked-list at runtime.
I'm well aware that a compiler can easily expand keyword arguments into regular ones. I strongly doubt your compiler will transform all the literal alists in your program into hash tables, and replace all the alist-ref functions and so on operating on them with the equivalent hash table functions. As long as alists are more syntactically blessed than hash tables, people will use them where another data structure would be more appropriate.
About the same.
(defn message [text & {:keys [style color]}]
...)
(message "Text" :style :bold :color :red)
Because typing those extra two brackets is apparently too much trouble. (defn message [text {:keys [style color]}] ...)
(message "Text" {:style :bold :color :red})
To the person asking, that {:keys [style color]} is destructuring, it's not required, but it's nice, it's equivalent to doing: (defn message [text opts]
(let [style (:style opts)
color (:color opts)]
...))Yes I agree with your later comment about syntactic blessing and all, but I think you picked a terrible example by choosing the single place in lisp where plists make more sense than hash tables.
(defun fun (a &key (b 0) (c 0)) ...)
(fun 5 :b 3)
into something like (defun fun (a b c) ...)
(fun 5 3 0)
Whether it does so as a regular macro or as a special form of the compiler doesn't matter, there's no need for there to be any difference in efficiency between representing keyword args with tables or plists.As I later mentioned in another comment, it was a mistake to talk about hash tables when I was really more interested in the abstract map datatype.
Named arguments had been introduced to Lisp with MDL (a Lisp dialect, brought to Lisp Machine Lisp and then to Common Lisp).
Using hash-tables for it is a step back from the view of development support.
; CL keyword arg syntax, taken from Practical Common Lisp
(defun foo (&key (a 0) (b 0)) (+ a b))
(foo :a 1) -> 1
(foo :a 1 :b 2) -> 3
; hypothetical table keyword arg syntax
; clojure defines commas to be whitespace, you can pretend they aren't there if you want
(defun foo ({a: 0, b: 0}) (+ a b))
(foo {a: 1}) -> 1
(foo {a: 1, b: 2}) -> 3
I fail to see why the table syntax would be any less usable or introspectable by compilers or editors. They'd have the advantage (which would be shared with alists, if Common Lisp had used them for keyword args) of sharing the syntax for keyword args with a syntax for optional structure properties (think XML's attributes)http://frank.kank.net/essays/hash.html
Mind you - reader macros should be used with a degree of care otherwise you basically create completely new language. I remember working on a project where I got a drop of some code from one of the other organizations in the project (by tape, this was a long time ago) opening the file and wondering what language the code was written in and taking a while to realize that it was indeed Lisp - but one that had used reader macros to do strange and terrible things.
Mind you, once I learned about reader macros I went on to do my own crazy stuff with them - they are almost too powerful a feature (almost!).