Skip to content
Emacs Lisp functions for dealing with association lists and hash tables. Inspired by Clojure.
Emacs Lisp
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.


Type Name Latest commit message Commit time
Failed to load latest commit information.
LICENSE Change license to GPL. Jul 16, 2017


Emacs Lisp functions for dealing with associative structures in a uniform and functional way.

Inspired by Clojure, dash, and seq.el.

These functions can take association lists, hash tables, and in some cases vectors (where the index is considered the key).

This library copies the names and semantics of the Clojure standard library. If you know Clojure then just add a- to the function name. The only exceptions are:

  • a-alist is an association list contructor, it has no Clojure counterpart.
  • a-has-key? is the equivalent of Clojure's contains?. This historical naming mistake won't be fixed in Clojure, but we can fix it here.
  • predicates have both a ? and a -p version, e.g. a-has-key-p. Use the latter if you want greater consistency with existing Elisp code.

All functions in this library are pure, they do not mutate their arguments.


The one unique selling point for a.el is that it lets you reuse your Clojure experience in Emacs, so Clojure programmers can be productive quickly. If you are not experienced in Clojure, or you want to do things "the Emacs way", then consider these alternatives.

  • map.el comes bundled with recent Emacs versions
  • asoc.el Association list library
  • ht.el Hash table library
  • kv.el A collection of tools for dealing with key/value data structures such as plists, alists and hash-tables.


a.el relies on features that are part of Emacs 25, so you need Emacs 25 or later. There are no other dependencies.


a.el is available from Lambda Island ELPA. Add this to your ~/.emacs or ~/.emacs.d/init.el

(require 'package)
(add-to-list 'package-archives
             '("lambdaisland" . "") t)


(a-list :foo 5 :bar 6)
;;=> ((:foo . 5) (:bar . 6))

(setq m (a-list :foo 5 :bar 6))
(setq h (a-hash-table :abc 123 :def 456))

(a-associative? m)
;;=> t
(a-associative? h)
;;=> t

(a-get m :foo)
;;=> 5
(a-get h :abc)
;;=> 123

(a-assoc m :foo 7 :baq 20)
;;=> ((:baq . 20) (:foo . 7) (:bar . 6))
(a-assoc h :foo 7)
;;=> #s(hash-table ... (:abc 123 :def 456 :foo 7 ...))

(a-keys m)
;;=> (:foo :bar)
(a-keys h)
;;=> (:def :abc)

(a-vals m)
;;=> (5 6)
(a-vals h)
;;=> (456 123)

(a-equal m (a-list :bar 6 :foo 5))
;;=> t

(a-has-key? m :bar)
;;=> t

(a-count h)
;;=> 2

(a-dissoc m :foo)
;;=> ((:bar . 6))

(a-assoc-in (a-list :name "Arne")
            [:stats :score] 100)
;;=> ((:name . "Arne") (:stats . ((:score . 100))))

(a-merge m h (a-list :and :more))
;;=> ((:and . :more) (:abc . 123) (:def . 456) (:foo . 5) (:bar . 6))

(a-merge-with '+ m (a-list :foo 10))
;;=> ((:foo . 15) (:bar . 6))

(a-update (a-list :name "Arne") :name 'concat " Brasseur")
;;=> ((:name . "Arne Brasseur"))

(setq player (a-list :name "Arne" :stats (a-list :score 99)))
(a-update-in player  [:stats :score] '+ 1)
;;=> ((:name . "Arne") (:stats (:score . 100)))


© Arne Brasseur 2017

Distributed under the terms of the GNU General Public License, version 3.0 or later. See LICENSE.

You can’t perform that action at this time.