libera/#lisp - IRC Chatlog
Search
19:06:42
amazigh
I started with a big idea, then wrote 600 lines of shell, now when I look at it; it looks is so small compared to my Big Plan.
0:23:38
yottabyte
Can someone tell me the thought process about when to use an alist, plist, and hashtable in common lisp? I've rarely used alists, and plists feel a lot like hashtables to me
0:24:05
yottabyte
Like I don't even know when I'd want to use an alist. Regular lists of homogenous data make sense of course
0:29:45
pjb
yottabyte: the key of a-list can be anything, and you can also search for the value (rassoc)
0:30:40
pjb
yottabyte: the key of p-list is intended to be symbols. They cannot be numbers or characters. And if they're something else than symbols, it's difficult to handle them, since you have to keep references to the keys used.
0:31:24
pjb
yottabyte: the key of hash-tables can be anything, (you can adjust the test function between EQ, EQL, EQUAL and EQUALP), but you cannot search on the values (unless you enumerate them).
0:32:08
pjb
yottabyte: you can also use mere lists or vectors, with functions such as POSITION or FIND that take a :KEY (and a :TEST) parameter to extract the key from the stored object itself.
0:32:33
pjb
yottabyte: and once you have a sequence, you can also sort them to be able to do binary searches.
0:33:23
pjb
yottabyte: p-list are what functions get with &key arguments. So it's useful to use them for those arguments.
0:34:00
pjb
a-list and p-list are more efficient than hash-tables when they're small. (depending on the implementation, the break-even point is between 5 and 35 entries).
0:34:26
pjb
yottabyte: but in the end, the best is to avoid commiting to an implementation choice. Instead, use dictionaries.
0:34:59
pjb
yottabyte: Notably, a com.informatimago.common-lisp.cesarum.dictionary:adaptating-dictionary can change the implementation dynamically on the run.
0:39:32
White_Flame
another thing about alists is that you can push new values onto the head of the list, which will override the tail, and when you return to using the non-pushed list, those additions will be "undone" and you'll see the complete prior state
0:40:10
White_Flame
eg ((a . 1) (b . 2)), into ((b . 4) (a . 1) (b . 2)) to override B's value in a scope
0:41:31
pjb
yottabyte: so you don't have to choose between p-list, a-list, hash-table or other. The adaptative-dictionary class makes the choice for you.
0:42:49
pjb
yottabyte: the point here is that you should not choose to use a given set of operator (list*, getf, remf) vs. (acons, assoc, rassoc) vs. (gethash, remhash), etc.
0:43:19
pjb
yottabyte: instead, write your own dictionary-get dictionary-add dictionary-remove functional abstraction!
0:44:14
pjb
Now, for the choice between a-list and p-list, there's also the consideration that p-list literals are easier to write: (k1 v1 k2 v2 k3 v3) vs. ((k1 . v1) (k2 . v2) (k3 . v3))
0:45:00
pjb
So you may want to write your literals as p-lists. But it's trivial to convert them into a-list or hash-table, so that should not influence the choice too much.