Using xlisp assoc-lists in clojure

184 views
Skip to first unread message

hpw...@googlemail.com

unread,
Nov 18, 2013, 2:09:56 AM11/18/13
to clo...@googlegroups.com
Hello,

As a newbie coming from a autolisp/newLISP background I have a question about using xlisp assoc-lists in clojure.

I have huge databases form autolisp (from an autocad enviroment) in the form of nested assoc-lists.

Can I stay with that format and read them from clojure?

The first would be to emulate 'setq' 
This could be done with 'def' (with a single pair of symbol/expression)
(By the way: Can a multiform of def be done like (defm symbol1 expression1 ....symboln expressionn) by a macro)

The scond is the use of assoc-lists in clojure:

Is it wise to use them in clojure for huge data-lists?
How can I access them like I do in autolisp with it's 'assoc'.
Finding the sublist by its first member.
I do not see a equivalent command for lists in clojure.
clojures assoc command is completly different.
Can it be done with a macro?


Regards

Hans-Peter

Justin Smith

unread,
Nov 18, 2013, 8:14:23 AM11/18/13
to clo...@googlegroups.com
Typically in clojure we use hash-maps (represented literally as {}) where other lisps would use an alist.

Regarding reading assoc list literals, I wouldn't be surprised if someone had written this function already, but I doubt it is in the core language. I also don't think it would be hard to implement. It would probably be best to write a function that reads in nested xlisp alists and returns nested maps.

To add a key to a map in clojure (acons in xlisp) we use assoc. It is likely that xlisp allows multiple bindings to the same key in an alist - maps do not work that way and you would need something slightly more complex than just a map if you need that behavior.

To find a key in a map in clojure (assoc in xplisp) we use get. get is the function used if a map or keyword is used in the calling position.

Tassilo Horn

unread,
Nov 18, 2013, 10:54:31 AM11/18/13
to Justin Smith, clo...@googlegroups.com
Justin Smith <noise...@gmail.com> writes:

Hi Justin & Hans-Peter,

> Typically in clojure we use hash-maps (represented literally as {})
> where other lisps would use an alist.

One difference between alists and maps is that in alists a "key" can
occur multiple times, and then the first entry with that key shadows all
following entries with that key (with respect to retrieval with
`assoc`).

Well, that feature is probably not used very often, but if you can't
rule out its usage, you also can't convert alists to maps and expect
they're equivalent.

> Regarding reading assoc list literals, I wouldn't be surprised if
> someone had written this function already, but I doubt it is in the
> core language.

This should do the trick:

(defn alist-assoc [key alist]
(first (filter #(= key (first %)) alist)))

And to add a list to an alist one would use `cons` in Clojure just like
one would use `cons` in CL, Scheme, or Elisp, too.

Bye,
Tassilo

Cedric Greevey

unread,
Nov 18, 2013, 6:50:36 PM11/18/13
to clo...@googlegroups.com, Justin Smith
It would probably be better to convert to/from normal Clojure maps at the edges of the Clojure code. If the input is '((k1 v1) (k2 v2) (k3 v3) (k1 v4)) and we want the earliest occurrence of k1 to "win", then that suggests (into {} (reverse alist)). If the input's flattened that would be (into {} (reverse (partition 2 alist))). The reverse makes sure that into assoces {k1 v4} first and then overwrites it with {k1 v1}, so the earliest occurrence of k1 "wins". If conj onto a map rejects two-element lists (as opposed to vectors; I don't have the docs or a repl in front of me where I am right now) then you'll need a (map vec) in there or something as well.

Output is simpler; (seq amap) alone might suffice, but (map seq amap) should give you the '((k1 v1) (k2 v2) ...) form from prn, and (mapcat seq amap) '(k1 v1 k2 v2 ...).

Of course, if you want the key-shadowing behavior not as a cheap overwrite but as a kind of "stack", so that (drop 1) on the original example would result in (k1 v4) being a mapping, then you need something beyond a normal Clojure map -- possibly a map of keys to stacks of values (maintained in vectors, say), or a stack of maps, depending on the exact use case.



--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

hpw...@googlemail.com

unread,
Nov 20, 2013, 12:03:13 PM11/20/13
to clo...@googlegroups.com
Hello,

Thanks for the answers and code hints.

What a bit surprise me, is the fact that clojure is announced as 'a lisp' and is relativ poor on working with lists.
A long time ago I learned that 'lisp' was the agronym for 'ListProcessing'. ;-)
As I note, I am a longtime user of newLISP which is compared in list-processing functions a power horse.
But I do not want to blame the language at all, otherwise I would not be interested.
I still have to find the best way to get the wanted job done with minimal efforts.

Regards

Hans-Peter



Gary Trakhman

unread,
Nov 20, 2013, 12:19:58 PM11/20/13
to clo...@googlegroups.com
'Relatively bad at lists' ?

I think the thing that clojure's intentionally bad at is arbitrary nested mutation, so you're forced to be recursive about things and return values (this is how update-in and assoc-in are implemented), but this has nothing to do with data type.

Clojure provides simple (maybe not easy or familiar) components for manipulating data, which includes lists.

We should understand the core principles and tradeoffs the language makes before making judgments like this.


Justin Smith

unread,
Nov 21, 2013, 1:48:11 PM11/21/13
to clo...@googlegroups.com
The issue, as far as I am concerned, is not that clojure cannot do alists as any traditional lisp would (it can, quite easily, as has already been shown).

The real question is why you would use a linked list for associative data, when you have an associative type with better lookup time and a convenient read syntax?

user> (defn alput [m k v] (update-in m [k] conj v))
#'user/alput
user> (alput {} :a 0)
{:a (0)}
user> (alput {} :a 1)
{:a (1)}
user> (defn alget [m k] (first (get m k)))
#'user/alget
user> (alget '{:a (1 0)} :a)
1
user> (defn aldissoc [m k] (update-in m [k] rest))
#'user/aldissoc
user> (aldissoc '{:a (1 0)} :a)
{:a (0)}
user> (aldissoc *1 :a)
{:a ()}
Reply all
Reply to author
Forward
0 new messages