+++ /dev/null
-;;; a-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-
-(add-to-list 'load-path (directory-file-name
- (or (file-name-directory #$) (car load-path))))
-
-\f
-;;;### (autoloads nil "a" "a.el" (0 0 0 0))
-;;; Generated autoloads from a.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "a" '("a-")))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; coding: utf-8
-;; End:
-;;; a-autoloads.el ends here
+++ /dev/null
-;;; -*- no-byte-compile: t -*-
-(define-package "a" "20180907.953" "Associative data structure functions" '((emacs "25")) :commit "18966975db7110d0aac726be95b593e2fc3d44ed" :keywords '("lisp") :authors '(("Arne Brasseur" . "arneNOSPAMarnebrasseur.net")) :maintainer '("Arne Brasseur" . "arneNOSPAMarnebrasseur.net") :url "https://github.com/plexus/a.el")
+++ /dev/null
-;;; a.el --- Associative data structure functions -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2017 Arne Brasseur
-
-;; Author: Arne Brasseur <arneNOSPAMarnebrasseur.net>
-;; URL: https://github.com/plexus/a.el
-;; Package-Version: 20180907.953
-;; Keywords: lisp
-;; Version: 0.1.1
-;; Package-Requires: ((emacs "25"))
-
-;; This file is not part of GNU Emacs.
-
-;; This file is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-
-;; This file is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; Library for dealing with associative data structures: alists, hash-maps, and
-;; vectors (for vectors, the indices are treated as keys).
-;;
-;; This library is largely inspired by Clojure, it has many of the functions
-;; found in clojure.core, prefixed with `a-'. All functions treat their
-;; arguments as immutable, so e.g. `a-assoc' will clone the hash-table or alist
-;; it is given. Keep this in mind when writing performance sensitive code.
-
-;;; Code:
-
-(eval-when-compile (require 'subr-x)) ;; for things like hash-table-keys
-
-(require 'cl-lib)
-(require 'seq)
-
-(defun a-associative-p (obj)
- (or (not obj)
- (hash-table-p obj)
- (and (consp obj) (consp (car obj)))))
-
-(defalias 'a-associative? 'a-associative-p)
-
-(defun a-get (map key &optional not-found)
- "Return the value MAP mapped to KEY, NOT-FOUND or nil if key not present."
- (cond
- ;; own implementation instead of alist-get so keys are checked with equal
- ;; instead of eq
- ((listp map)
- (a--alist-get map key not-found))
-
- ((vectorp map)
- (if (a-has-key? map key)
- (aref map key)
- not-found))
-
- ((hash-table-p map)
- (gethash key map not-found))
- (t (user-error "Not associative: %S" map))))
-
-(defun a--alist-get (map key &optional not-found)
- "Like alist-get, but uses equal instead of eq to look up in map MAP key KEY.
-Returns NOT-FOUND if the key is not present, or `nil' if
-NOT-FOUND is not specified."
- (cl-block nil
- (seq-doseq (pair map)
- (when (equal (car pair) key)
- (cl-return (cdr pair))))
- not-found))
-
-(defun a-get-in (m ks &optional not-found)
- "Look up a value in a nested associative structure.
-
-Given a data structure M, and a sequence of keys KS, find the
-value found by using each key in turn to do a lookup in the next
-\"layer\". Return `nil' if the key is not present, or the NOT-FOUND
-value if supplied."
- (let ((result m))
- (cl-block nil
- (seq-doseq (k ks)
- (if (a-has-key? result k)
- (setq result (a-get result k))
- (cl-return not-found)))
- result)))
-
-(defmacro a-get* (&rest keys)
- "Look up a value in a nested associative structure.
-
-Like a-get-in, but takes the key sequence KEYS directly as vararg
-arguments, rather than as a single sequence."
- (cl-labels ((rec (keys)
- `(a-get ,(if (and (consp (cdr keys))
- (cddr keys))
- (rec (cdr keys))
- (cadr keys))
- ,(car keys))))
- (rec (nreverse keys))))
-
-(defun a-has-key (coll k)
- "Check if the given associative collection COLL has a certain key K."
- (cond
- ((listp coll) (not (eq (a--alist-get coll k :not-found) :not-found)))
- ((vectorp coll) (and (integerp k) (< -1 k (length coll))))
- ((hash-table-p coll) (not (eq (gethash k coll :not-found) :not-found)))
- (t (user-error "Not associative: %S" coll))))
-
-(defalias 'a-has-key? 'a-has-key)
-
-(defun a-assoc-1 (coll k v)
- "Like `a-assoc', (in COLL assoc K with V) but only takes a single k-v pair.
-Internal helper function."
- (cond
- ((listp coll)
- (if (a-has-key? coll k)
- (mapcar (lambda (entry)
- (if (equal (car entry) k)
- (cons k v)
- entry))
- coll)
- (cons (cons k v) coll)))
-
- ((vectorp coll)
- (if (and (integerp k) (> k 0))
- (if (< k (length coll))
- (let ((copy (copy-sequence coll)))
- (aset copy k v)
- copy)
- (vconcat coll (make-list (- k (length coll)) nil) (list v)))))
-
- ((hash-table-p coll)
- (let ((copy (copy-hash-table coll)))
- (puthash k v copy)
- copy))))
-
-(defun a-assoc (coll &rest kvs)
- "Return an updated collection COLL, associating values with keys KVS."
- (when (not (cl-evenp (a-count kvs)))
- (user-error "a-assoc requires an even number of arguments!"))
- (seq-reduce (lambda (coll kv)
- (seq-let [k v] kv
- (a-assoc-1 coll k v)))
- (seq-partition kvs 2)
- coll))
-
-(defun a-keys (coll)
- "Return the keys in the collection COLL."
- (cond
- ((listp coll)
- (mapcar #'car coll))
-
- ((hash-table-p coll)
- (hash-table-keys coll))))
-
-(defun a-vals (coll)
- "Return the values in the collection COLL."
- (cond
- ((listp coll)
- (mapcar #'cdr coll))
-
- ((hash-table-p coll)
- (hash-table-values coll))))
-
-(defun a-reduce-kv (fn from coll)
- "Reduce with FN starting from FROM the collection COLL.
-Reduce an associative collection COLL, starting with an initial
-value of FROM. The reducing function FN receives the intermediate
-value, key, and value."
- (seq-reduce (lambda (acc key)
- (funcall fn acc key (a-get coll key)))
- (a-keys coll)
- from))
-
-(defun a-count (coll)
- "Count the number of key-value pairs in COLL.
-Like length, but can also return the length of hash tables."
- (cond
- ((seqp coll)
- (length coll))
-
- ((hash-table-p coll)
- (hash-table-count coll))))
-
-(defun a-equal (a b)
- "Compare collections A, B for value equality.
-
-Associative collections (hash tables and a-lists) are considered
-equal if they contain equal key-value pairs, regardless of order.
-
-Sequences (lists or vectors) are considered equal if they contain
-the same elements in the same order.
-
-Collection elements are compared using `a-equal'. In other words,
-the equality check is recursive, resulting in a \"deep\" equality
-check.
-
-Anything that isn't associative or a sequence is compared with
-`equal'."
- (cond
- ((and (a-associative? a) (a-associative? b))
- (or (equal a b)
- (when (eq (a-count a) (a-count b))
- (cl-block nil
- (seq-doseq (k (a-keys a))
- (when (not (a-equal (a-get a k) (a-get b k)))
- (cl-return nil)))
- t))))
- ((and (sequencep a) (sequencep b))
- (and (eq (length a) (length b))
- (or (and (seq-empty-p a) (seq-empty-p b))
- (and (a-equal (elt a 0) (elt b 0))
- (a-equal (seq-drop a 1) (seq-drop b 1))))))
- (t
- (equal a b))))
-
-(defalias 'a-equal? 'a-equal)
-
-(defun a-merge (&rest colls)
- "Merge multiple associative collections.
-Return the type of the first collection COLLS."
- (seq-reduce (lambda (this that)
- (a-reduce-kv (lambda (coll k v)
- (a-assoc coll k v))
- this
- that))
- (cdr colls)
- (car colls)))
-
-(defun a-merge-with (f &rest colls)
- "Merge multiple associative collections.
-Return the type of the first collection COLLS. If a key exists in
-both, then combine the associated values by calling f on them."
- (seq-reduce (lambda (this that)
- (a-reduce-kv (lambda (coll k v)
- (a-assoc coll k (if (a-has-key coll k)
- (funcall f v (a-get coll k))
- v)))
- this
- that))
- (cdr colls)
- (car colls)))
-
-(defun a-alist (&rest kvs)
- "Create an association list from the given keys and values KVS.
-Arguments are simply provided in sequence, rather than as lists or cons cells.
-For example: (a-alist :foo 123 :bar 456)"
- (mapcar (lambda (kv) (cons (car kv) (cadr kv))) (seq-partition kvs 2)))
-
-(defalias 'a-list 'a-alist)
-
-(defun a-hash-table (&rest kvs)
- "Create a hash table from the given keys and values KVS.
-Arguments are simply provided in sequence, rather than as lists
-or cons cells. As \"test\" for the hash table, equal is used. The
-hash table is created without extra storage space, so with a size
-equal to amount of key-value pairs, since it is assumed to be
-treated as immutable.
-For example: (a-hash-table :foo 123 :bar 456)"
- (let* ((kv-pairs (seq-partition kvs 2))
- (hash-map (make-hash-table :test 'equal :size (length kv-pairs))))
- (seq-do (lambda (pair)
- (puthash (car pair) (cadr pair) hash-map))
- kv-pairs)
- hash-map))
-
-(defun a-assoc-in (coll keys value)
- "In collection COLL, at location KEYS, associate value VALUE.
-Associates a value in a nested associative collection COLL, where
-KEYS is a sequence of keys and VALUE is the new value and returns
-a new nested structure. If any levels do not exist, association
-lists will be created."
- (cl-case (length keys)
- (0 coll)
- (1 (a-assoc-1 coll (elt keys 0) value))
- (t (a-assoc-1 coll
- (elt keys 0)
- (a-assoc-in (a-get coll (elt keys 0))
- (seq-drop keys 1)
- value)))))
-
-(defun a-dissoc--list (list keys)
- "Return updated LIST with KEYS removed.
-Internal helper. Use `a-dissoc' instead."
- (a-reduce-kv (lambda (res k v)
- (if (member k keys)
- res
- (cons (cons k v) res)))
- nil
- list))
-
-(defun a-dissoc--hash-table (table keys)
- "Return updated TABLE with KEYS removed.
-Internal helper. Use `a-dissoc' instead."
- (let ((new-table (make-hash-table :size (hash-table-count table)
- :test (hash-table-test table)))
- (rest-keys (seq-remove (lambda (k)
- (member k keys))
- (a-keys table))))
- (seq-doseq (k rest-keys)
- (puthash k (gethash k table) new-table))
- new-table))
-
-(defun a-dissoc (coll &rest keys)
- "Return an updated version of collection COLL with the KEY removed."
- (cond
- ((listp coll) (a-dissoc--list coll keys))
- ((hash-table-p coll) (a-dissoc--hash-table coll keys))))
-
-(defun a-update (coll key fn &rest args)
- "In collection COLL, at location KEY, apply FN with extra args ARGS.
-'Updates' a value in an associative collection COLL, where KEY is
-a key and FN is a function that will take the old value and any
-supplied args and return the new value, and returns a new
-structure. If the key does not exist, nil is passed as the old
-value."
- (a-assoc-1 coll
- key
- (apply #'funcall fn (a-get coll key) args)))
-
-(defun a-update-in (coll keys fn &rest args)
- "In collection COLL, at location KEYS, apply FN with extra args ARGS.
-'Updates' a value in a nested associative collection COLL, where
-KEYS is a sequence of keys and FN is a function that will take
-the old value and any supplied ARGS and return the new value, and
-returns a new nested structure. If any levels do not exist,
-association lists will be created."
- (cl-case (length keys)
- (0 coll)
- (1 (apply #'a-update coll (elt keys 0) fn args))
- (t (a-assoc-1 coll
- (elt keys 0)
- (apply #'a-update-in
- (a-get coll (elt keys 0))
- (seq-drop keys 1)
- fn
- args)))))
-
-(provide 'a)
-;;; a.el ends here
--- /dev/null
+;;; a-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+ (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "a" "a.el" (0 0 0 0))
+;;; Generated autoloads from a.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "a" '("a-")))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; a-autoloads.el ends here
--- /dev/null
+;;; Generated package description from a.el -*- no-byte-compile: t -*-
+(define-package "a" "20210929.1510" "Associative data structure functions" '((emacs "25")) :commit "9ad2d18252b729174fe22ed0b2b7670c88f60c31" :authors '(("Arne Brasseur" . "arneNOSPAMarnebrasseur.net")) :maintainer '("Arne Brasseur" . "arneNOSPAMarnebrasseur.net") :keywords '("lisp") :url "https://github.com/plexus/a.el")
--- /dev/null
+;;; a.el --- Associative data structure functions -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017-2021 Arne Brasseur
+
+;; Author: Arne Brasseur <arneNOSPAMarnebrasseur.net>
+;; URL: https://github.com/plexus/a.el
+;; Package-Version: 20210929.1510
+;; Package-Commit: 9ad2d18252b729174fe22ed0b2b7670c88f60c31
+;; Keywords: lisp
+;; Version: 1.0.0
+;; Package-Requires: ((emacs "25"))
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; Library for dealing with associative data structures: alists, hash-maps, and
+;; vectors (for vectors, the indices are treated as keys).
+;;
+;; This library is largely inspired by Clojure, it has many of the functions
+;; found in clojure.core, prefixed with `a-'. All functions treat their
+;; arguments as immutable, so e.g. `a-assoc' will clone the hash-table or alist
+;; it is given. Keep this in mind when writing performance sensitive code.
+
+;;; Code:
+
+(eval-when-compile (require 'subr-x)) ;; for things like hash-table-keys
+
+(require 'cl-lib)
+(require 'seq)
+
+(defun a-associative-p (obj)
+ (or (not obj)
+ (hash-table-p obj)
+ (and (consp obj)
+ (consp (car obj)))))
+
+(defalias 'a-associative? 'a-associative-p)
+
+(defun a-get (map key &optional not-found)
+ "Return the value MAP mapped to KEY, NOT-FOUND or nil if key not present."
+ (cond
+ ;; own implementation instead of alist-get so keys are checked with equal
+ ;; instead of eq
+ ((listp map)
+ (a--alist-get map key not-found))
+
+ ((vectorp map)
+ (if (a-has-key? map key)
+ (aref map key)
+ not-found))
+
+ ((hash-table-p map)
+ (gethash key map not-found))
+ (t (user-error "Not associative: %S" map))))
+
+(defun a--alist-get (map key &optional not-found)
+ "Like alist-get, but uses equal instead of eq to look up in map MAP key KEY.
+Returns NOT-FOUND if the key is not present, or `nil' if
+NOT-FOUND is not specified."
+ (cl-block nil
+ (seq-doseq (pair map)
+ (when (equal (car pair) key)
+ (cl-return (cdr pair))))
+ not-found))
+
+(defun a-get-in (m ks &optional not-found)
+ "Look up a value in a nested associative structure.
+
+Given a data structure M, and a sequence of keys KS, find the
+value found by using each key in turn to do a lookup in the next
+\"layer\". Return `nil' if the key is not present, or the NOT-FOUND
+value if supplied."
+ (let ((result m))
+ (cl-block nil
+ (seq-doseq (k ks)
+ (if (a-has-key? result k)
+ (setq result (a-get result k))
+ (cl-return not-found)))
+ result)))
+
+(defmacro a-get* (&rest keys)
+ "Look up a value in a nested associative structure.
+
+Like a-get-in, but takes the key sequence KEYS directly as vararg
+arguments, rather than as a single sequence."
+ (cl-labels ((rec (keys)
+ `(a-get ,(if (and (consp (cdr keys))
+ (cddr keys))
+ (rec (cdr keys))
+ (cadr keys))
+ ,(car keys))))
+ (rec (nreverse keys))))
+
+(defun a-has-key (coll k)
+ "Check if the given associative collection COLL has a certain key K."
+ (cond
+ ((listp coll) (not (eq (a--alist-get coll k :not-found) :not-found)))
+ ((vectorp coll) (and (integerp k) (< -1 k (length coll))))
+ ((hash-table-p coll) (not (eq (gethash k coll :not-found) :not-found)))
+ (t (user-error "Not associative: %S" coll))))
+
+(defalias 'a-has-key? 'a-has-key)
+
+(defun a-assoc-1 (coll k v)
+ "Like `a-assoc', (in COLL assoc K with V) but only takes a single k-v pair.
+Internal helper function."
+ (cond
+ ((listp coll)
+ (if (a-has-key? coll k)
+ (mapcar (lambda (entry)
+ (if (equal (car entry) k)
+ (cons k v)
+ entry))
+ coll)
+ (cons (cons k v) coll)))
+
+ ((vectorp coll)
+ (if (and (integerp k) (>= k 0))
+ (if (< k (length coll))
+ (let ((copy (copy-sequence coll)))
+ (aset copy k v)
+ copy)
+ (vconcat coll (make-list (- k (length coll)) nil) (list v)))))
+
+ ((hash-table-p coll)
+ (let ((copy (copy-hash-table coll)))
+ (puthash k v copy)
+ copy))))
+
+(defun a-assoc (coll &rest kvs)
+ "Return an updated collection COLL, associating values with keys KVS."
+ (when (not (cl-evenp (a-count kvs)))
+ (user-error "a-assoc requires an even number of arguments!"))
+ (seq-reduce (lambda (coll kv)
+ (seq-let [k v] kv
+ (a-assoc-1 coll k v)))
+ (seq-partition kvs 2)
+ coll))
+
+(defun a-keys (coll)
+ "Return the keys in the collection COLL."
+ (cond
+ ((listp coll)
+ (mapcar #'car coll))
+
+ ((hash-table-p coll)
+ (hash-table-keys coll))))
+
+(defun a-vals (coll)
+ "Return the values in the collection COLL."
+ (cond
+ ((listp coll)
+ (mapcar #'cdr coll))
+
+ ((hash-table-p coll)
+ (hash-table-values coll))))
+
+(defun a-reduce-kv (fn from coll)
+ "Reduce with FN starting from FROM the collection COLL.
+Reduce an associative collection COLL, starting with an initial
+value of FROM. The reducing function FN receives the intermediate
+value, key, and value."
+ (seq-reduce (lambda (acc key)
+ (funcall fn acc key (a-get coll key)))
+ (a-keys coll)
+ from))
+
+(defun a-count (coll)
+ "Count the number of key-value pairs in COLL.
+Like length, but can also return the length of hash tables."
+ (cond
+ ((seqp coll)
+ (length coll))
+
+ ((hash-table-p coll)
+ (hash-table-count coll))))
+
+(defun a-equal (a b)
+ "Compare collections A, B for value equality.
+
+Associative collections (hash tables and a-lists) are considered
+equal if they contain equal key-value pairs, regardless of order.
+
+Sequences (lists or vectors) are considered equal if they contain
+the same elements in the same order.
+
+Collection elements are compared using `a-equal'. In other words,
+the equality check is recursive, resulting in a \"deep\" equality
+check.
+
+Anything that isn't associative or a sequence is compared with
+`equal'."
+ (cond
+ ((and (a-associative? a) (a-associative? b))
+ (or (equal a b)
+ (when (eq (a-count a) (a-count b))
+ (cl-block nil
+ (seq-doseq (k (a-keys a))
+ (when (not (and
+ (a-has-key b k)
+ (a-equal (a-get a k) (a-get b k))))
+ (cl-return nil)))
+ (seq-doseq (k (a-keys b))
+ (when (not (and
+ (a-has-key a k)
+ (a-equal (a-get a k) (a-get b k))))
+ (cl-return nil)))
+ t))))
+ ((and (sequencep a) (sequencep b))
+ (and (eq (length a) (length b))
+ (or (and (seq-empty-p a) (seq-empty-p b))
+ (and (a-equal (elt a 0) (elt b 0))
+ (a-equal (seq-drop a 1) (seq-drop b 1))))))
+ (t
+ (equal a b))))
+
+(defalias 'a-equal? 'a-equal)
+
+(defun a-merge (&rest colls)
+ "Merge multiple associative collections.
+Return the type of the first collection COLLS."
+ (seq-reduce (lambda (this that)
+ (a-reduce-kv (lambda (coll k v)
+ (a-assoc coll k v))
+ this
+ that))
+ (cdr colls)
+ (car colls)))
+
+(defun a-merge-with (f &rest colls)
+ "Merge multiple associative collections.
+Return the type of the first collection COLLS. If a key exists in
+both, then combine the associated values by calling f on them."
+ (seq-reduce (lambda (this that)
+ (a-reduce-kv (lambda (coll k v)
+ (a-assoc coll k (if (a-has-key coll k)
+ (funcall f v (a-get coll k))
+ v)))
+ this
+ that))
+ (cdr colls)
+ (car colls)))
+
+(defun a-alist (&rest kvs)
+ "Create an association list from the given keys and values KVS.
+Arguments are simply provided in sequence, rather than as lists or cons cells.
+For example: (a-alist :foo 123 :bar 456)"
+ (mapcar (lambda (kv) (cons (car kv) (cadr kv))) (seq-partition kvs 2)))
+
+(defalias 'a-list 'a-alist)
+
+(defun a-hash-table (&rest kvs)
+ "Create a hash table from the given keys and values KVS.
+Arguments are simply provided in sequence, rather than as lists
+or cons cells. As \"test\" for the hash table, equal is used. The
+hash table is created without extra storage space, so with a size
+equal to amount of key-value pairs, since it is assumed to be
+treated as immutable.
+For example: (a-hash-table :foo 123 :bar 456)"
+ (let* ((kv-pairs (seq-partition kvs 2))
+ (hash-map (make-hash-table :test 'equal :size (length kv-pairs))))
+ (seq-do (lambda (pair)
+ (puthash (car pair) (cadr pair) hash-map))
+ kv-pairs)
+ hash-map))
+
+(defun a-assoc-in (coll keys value)
+ "In collection COLL, at location KEYS, associate value VALUE.
+Associates a value in a nested associative collection COLL, where
+KEYS is a sequence of keys and VALUE is the new value and returns
+a new nested structure. If any levels do not exist, association
+lists will be created."
+ (cl-case (length keys)
+ (0 coll)
+ (1 (a-assoc-1 coll (elt keys 0) value))
+ (t (a-assoc-1 coll
+ (elt keys 0)
+ (a-assoc-in (a-get coll (elt keys 0))
+ (seq-drop keys 1)
+ value)))))
+
+(defun a-dissoc--list (list keys)
+ "Return updated LIST with KEYS removed.
+Internal helper. Use `a-dissoc' instead."
+ (a-reduce-kv (lambda (res k v)
+ (if (member k keys)
+ res
+ (cons (cons k v) res)))
+ nil
+ list))
+
+(defun a-dissoc--hash-table (table keys)
+ "Return updated TABLE with KEYS removed.
+Internal helper. Use `a-dissoc' instead."
+ (let ((new-table (make-hash-table :size (hash-table-count table)
+ :test (hash-table-test table)))
+ (rest-keys (seq-remove (lambda (k)
+ (member k keys))
+ (a-keys table))))
+ (seq-doseq (k rest-keys)
+ (puthash k (gethash k table) new-table))
+ new-table))
+
+(defun a-dissoc (coll &rest keys)
+ "Return an updated version of collection COLL with the KEY removed."
+ (cond
+ ((listp coll) (a-dissoc--list coll keys))
+ ((hash-table-p coll) (a-dissoc--hash-table coll keys))))
+
+(defun a-update (coll key fn &rest args)
+ "In collection COLL, at location KEY, apply FN with extra args ARGS.
+'Updates' a value in an associative collection COLL, where KEY is
+a key and FN is a function that will take the old value and any
+supplied args and return the new value, and returns a new
+structure. If the key does not exist, nil is passed as the old
+value."
+ (a-assoc-1 coll
+ key
+ (apply #'funcall fn (a-get coll key) args)))
+
+(defun a-update-in (coll keys fn &rest args)
+ "In collection COLL, at location KEYS, apply FN with extra args ARGS.
+'Updates' a value in a nested associative collection COLL, where
+KEYS is a sequence of keys and FN is a function that will take
+the old value and any supplied ARGS and return the new value, and
+returns a new nested structure. If any levels do not exist,
+association lists will be created."
+ (cl-case (length keys)
+ (0 coll)
+ (1 (apply #'a-update coll (elt keys 0) fn args))
+ (t (a-assoc-1 coll
+ (elt keys 0)
+ (apply #'a-update-in
+ (a-get coll (elt keys 0))
+ (seq-drop keys 1)
+ fn
+ args)))))
+
+(provide 'a)
+
+;;; a.el ends here