diff options
Diffstat (limited to 'emacs/.emacs.d/wpc/alist.el')
-rw-r--r-- | emacs/.emacs.d/wpc/alist.el | 120 |
1 files changed, 62 insertions, 58 deletions
diff --git a/emacs/.emacs.d/wpc/alist.el b/emacs/.emacs.d/wpc/alist.el index 574960a89276..f9d2be71fb8e 100644 --- a/emacs/.emacs.d/wpc/alist.el +++ b/emacs/.emacs.d/wpc/alist.el @@ -1,5 +1,9 @@ ;;; alist.el --- Interface for working with associative lists -*- lexical-binding: t -*- + ;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; URL: https://git.wpcarro.dev/wpcarro/briefcase +;; Package-Requires: ((emacs "25.1")) ;;; Commentary: ;; Firstly, a rant: @@ -89,7 +93,7 @@ ;; Constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defconst alist/enable-tests? t +(defconst alist-enable-tests? t "When t, run the test suite.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -97,21 +101,21 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TODO: Support a variadic version of this to easily construct alists. -(defun alist/new () +(defun alist-new () "Return a new, empty alist." '()) ;; Create ;; TODO: See if this mutates. -(defun alist/set (k v xs) +(defun alist-set (k v xs) "Set K to V in XS." - (if (alist/has-key? k xs) + (if (alist-has-key? k xs) (progn (setf (alist-get k xs) v) xs) - (list/cons `(,k . ,v) xs))) + (list-cons `(,k . ,v) xs))) -(defun alist/set! (k v xs) +(defun alist-set! (k v xs) "Set K to V in XS mutatively. Note that this doesn't append to the alist in the way that most alists handle writing. If the k already exists in XS, it is overwritten." @@ -119,113 +123,113 @@ Note that this doesn't append to the alist in the way that most alists handle (map-put xs k v)) ;; Read -(defun alist/get (k xs) +(defun alist-get (k xs) "Return the value at K in XS; otherwise, return nil. Returns the first occurrence of K in XS since alists support multiple entries." (cdr (assoc k xs))) -(defun alist/get-entry (k xs) +(defun alist-get-entry (k xs) "Return the first key-value pair at K in XS." (assoc k xs)) ;; Update ;; TODO: Add warning about only the first occurrence being updated in the ;; documentation. -(defun alist/update (k f xs) +(defun alist-update (k f xs) "Apply F to the value stored at K in XS. -If `K' is not in `XS', this function errors. Use `alist/upsert' if you're +If `K' is not in `XS', this function errors. Use `alist-upsert' if you're interested in inserting a value when a key doesn't already exist." - (if (maybe-nil? (alist/get k xs)) + (if (maybe-nil? (alist-get k xs)) (error "Refusing to update: key does not exist in alist") - (alist/set k (funcall f (alist/get k xs)) xs))) + (alist-set k (funcall f (alist-get k xs)) xs))) -(defun alist/update! (k f xs) +(defun alist-update! (k f xs) "Call F on the entry at K in XS. -Mutative variant of `alist/update'." - (alist/set! k (funcall f (alist/get k xs))xs)) +Mutative variant of `alist-update'." + (alist-set! k (funcall f (alist-get k xs))xs)) ;; TODO: Support this. -(defun alist/upsert (k v f xs) +(defun alist-upsert (k v f xs) "If K exists in `XS' call `F' on the value otherwise insert `V'." - (if (alist/get k xs) - (alist/update k f xs) - (alist/set k v xs))) + (if (alist-get k xs) + (alist-update k f xs) + (alist-set k v xs))) ;; Delete ;; TODO: Make sure `delete' and `remove' behave as advertised in the Elisp docs. -(defun alist/delete (k xs) +(defun alist-delete (k xs) "Deletes the entry of K from XS. This only removes the first occurrence of K, since alists support multiple - key-value entries. See `alist/delete-all' and `alist/dedupe'." + key-value entries. See `alist-delete-all' and `alist-dedupe'." (remove (assoc k xs) xs)) -(defun alist/delete! (k xs) +(defun alist-delete! (k xs) "Delete the entry of K from XS. -Mutative variant of `alist/delete'." +Mutative variant of `alist-delete'." (delete (assoc k xs) xs)) ;; Additions to the CRUD API ;; TODO: Implement this function. -(defun alist/dedupe-keys (xs) +(defun alist-dedupe-keys (xs) "Remove the entries in XS where the keys are `equal'.") -(defun alist/dedupe-entries (xs) +(defun alist-dedupe-entries (xs) "Remove the entries in XS where the key-value pair are `equal'." (delete-dups xs)) -(defun alist/keys (xs) +(defun alist-keys (xs) "Return a list of the keys in XS." (mapcar 'car xs)) -(defun alist/values (xs) +(defun alist-values (xs) "Return a list of the values in XS." (mapcar 'cdr xs)) -(defun alist/has-key? (k xs) +(defun alist-has-key? (k xs) "Return t if XS has a key `equal' to K." (maybe-some? (assoc k xs))) -(defun alist/has-value? (v xs) +(defun alist-has-value? (v xs) "Return t if XS has a value of V." (maybe-some? (rassoc v xs))) -(defun alist/count (xs) +(defun alist-count (xs) "Return the number of entries in XS." (length xs)) -;; TODO: Should I support `alist/find-key' and `alist/find-value' variants? -(defun alist/find (p xs) +;; TODO: Should I support `alist-find-key' and `alist-find-value' variants? +(defun alist-find (p xs) "Apply a predicate fn, P, to each key and value in XS and return the key of the first element that returns t." - (let ((result (list/find (lambda (x) (funcall p (car x) (cdr x))) xs))) + (let ((result (list-find (lambda (x) (funcall p (car x) (cdr x))) xs))) (if result (car result) nil))) -(defun alist/map-keys (f xs) +(defun alist-map-keys (f xs) "Call F on the values in XS, returning a new alist." - (list/map (lambda (x) + (list-map (lambda (x) `(,(funcall f (car x)) . ,(cdr x))) xs)) -(defun alist/map-values (f xs) +(defun alist-map-values (f xs) "Call F on the values in XS, returning a new alist." - (list/map (lambda (x) + (list-map (lambda (x) `(,(car x) . ,(funcall f (cdr x)))) xs)) -(defun alist/reduce (acc f xs) +(defun alist-reduce (acc f xs) "Return a new alist by calling F on k v and ACC from XS. F should return a tuple. See tuple.el for more information." - (->> (alist/keys xs) - (list/reduce acc + (->> (alist-keys xs) + (list-reduce acc (lambda (k acc) - (funcall f k (alist/get k xs) acc))))) + (funcall f k (alist-get k xs) acc))))) -(defun alist/merge (a b) +(defun alist-merge (a b) "Return a new alist with a merge of alists, A and B. In this case, the last writer wins, which is B." - (alist/reduce a #'alist/set b)) + (alist-reduce a #'alist-set b)) ;; TODO: Support `-all' variants like: ;; - get-all @@ -239,34 +243,34 @@ In this case, the last writer wins, which is B." (first-name . "William") (last-name . "Carroll") (last-name . "Another"))) - (alist/set 'last-name "Van Gogh" person) - (alist/get 'last-name person) - (alist/update 'last-name (lambda (x) "whoops") person) - (alist/delete 'first-name person) - (alist/keys person) - (alist/values person) - (alist/count person) - (alist/has-key? 'first-name person) - (alist/has-value? "William" person) - ;; (alist/dedupe-keys person) - (alist/dedupe-entries person) - (alist/count person))) + (alist-set 'last-name "Van Gogh" person) + (alist-get 'last-name person) + (alist-update 'last-name (lambda (x) "whoops") person) + (alist-delete 'first-name person) + (alist-keys person) + (alist-values person) + (alist-count person) + (alist-has-key? 'first-name person) + (alist-has-value? "William" person) + ;; (alist-dedupe-keys person) + (alist-dedupe-entries person) + (alist-count person))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(when alist/enable-tests? +(when alist-enable-tests? (prelude-assert (equal '((2 . one) (3 . two)) - (alist/map-keys #'1+ + (alist-map-keys #'1+ '((1 . one) (2 . two))))) (prelude-assert (equal '((one . 2) (two . 3)) - (alist/map-values #'1+ + (alist-map-values #'1+ '((one . 1) (two . 2)))))) |