This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-09
Channels
- # aleph (1)
- # asami (5)
- # babashka (4)
- # beginners (8)
- # biff (19)
- # calva (2)
- # cider (14)
- # clojure (17)
- # clojure-dev (3)
- # clojure-europe (3)
- # clojurescript (2)
- # community-development (9)
- # conjure (1)
- # core-typed (2)
- # datomic (6)
- # emacs (20)
- # gratitude (1)
- # helix (5)
- # kaocha (4)
- # nbb (1)
- # releases (3)
- # testing (17)
An elisp alist with duplicate keys is valid. Even the https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html mention the use of duplicate keys: > Association lists are often used to record information that you might otherwise keep on a stack... Of course, a Clojure map doesn't play that game. However, https://github.com/clojure-emacs/parseedn produces invalid edn in this case:
(parseedn-print-str '((:x 1) (:x 2)))
;; "{:x (1), :x (1)}"
Not sure what the best solution would be. Deleting keys wouldn't be nice, nor would an incidental map-or-list.
Is there a workaround I haven't considered? Maybe alists just shouldn't be maps?This seems a straightforward bug? Alists are ordered and earlier keys shadow later keys right?
That alist, as an associative structure, has only a single key. The map it was printed as is invalid. Seems just a bug
> earlier keys shadow later keys
That's true as far as the alist interface is concerned. The later keys still have meaning, though, and they're accessible via the ordinary list.
In my use-case, I receive a list of lists from org-element-parse-buffer
. I need all of them, and I don't care if the list is associative.
Or, at least, some representation of the later keys.
You're right, though, "{:x (1), :x (1)}"
is definitely a bug. Nobody needs the top of the stack twice in an invalid map.
actually it seems like it treats all tuples as maps. (parseedn-print (vector (vector ':x 1) (vector ':x 2)))
so you’ll have to munge the data a bit but that’s fair as you are taking an associate item and treating it like a seq
and to figure all this out i’m just looking at the source of parseedn-print
. and the vectorp
clause is easy to see
Cool, I'm on the way to a good workaround, with something like:
(parseedn-print-str (vconcat [] '((:x 1) (:x 2))))
;; "[{:x 1} {:x 2}]"
Thanks for thinking through it with me.I bet you want all of the cons cells to be vectors instead of single key maps but maybe it doesn’t matter
If the parseedn functions had an option to ignore associative constructs entirely, that could be a reasonable solution.
(defun list->vec (l)
(if (not (listp l)) l
(vconcat [] l)))
(parseedn-print-str
(list->vec (mapcar #'list->vec '((:x 1) (:x 2)))))
;; "[[:x 1] [:x 2]]"
I'm building an emacs function that will display the keys in a map so you can select it. The attached image might help give you an idea of what this feels like.
Here is the code so far, suggestions welcome. For instance, thinking I can probably swap the helm stuff out for the more generic function completing-read-multiple
(defun my-multi-select-function (callback keys)
(interactive)
(helm :sources (helm-build-sync-source "Choose items"
:candidates keys
:action (lambda (candidate)
(funcall callback (helm-marked-candidates))))
:buffer "*helm multi-select*"
:candidate-number-limit 9999))
(defun insert-selected-keys (selected-items)
;; (insert (mapconcat 'identity selected-items ", "))
(insert
(if (equal 1 (length selected-items))
(car selected-items)
(format-list selected-items)
)))
(defun clojure-keys ()
(interactive)
;; call keys on the map and get the result
(cider-interactive-eval "(keys *1)")
;; hacky sleep to avoid register not being ready
(sit-for 0.25)
(my-multi-select-function #'insert-selected-keys (get-keys-from-cider-regsiter)))
(defun get-keys-from-cider-regsiter ()
(mapcar (lambda (k) (format "%s" k)) (car (read-from-string (get-register ?e)))))
(global-set-key (kbd "C-c s") #'clojure-keys)
(defun format-list (lst)
"Takes a list and returns a formatted string.
If the list has only one item, returns the item.
If the list has multiple items, returns the list inside a string with the 'select-keys' prefix."
(if (= (length lst) 1)
(car lst)
(format "(select-keys [%s])" (mapconcat 'identity lst " "))))
Hey that's a really cool idea, I like it!