diff options
author | Blendoit <blendoit@gmail.com> | 2020-08-01 15:18:40 -0700 |
---|---|---|
committer | Blendoit <blendoit@gmail.com> | 2020-08-01 15:18:40 -0700 |
commit | 374ae3de24187512adddf01a56e5eb52c79db65f (patch) | |
tree | 847adf6824b56394f5a040ba45863e2dbdceac70 /elpa/dash-20200524.1947 | |
parent | 54fbf6576cf2dd94ef5af332a6075723a9dfa8b3 (diff) |
Include contents of elpa/ sources + theme update.
Diffstat (limited to 'elpa/dash-20200524.1947')
-rw-r--r-- | elpa/dash-20200524.1947/dash-autoloads.el | 26 | ||||
-rw-r--r-- | elpa/dash-20200524.1947/dash-pkg.el | 9 | ||||
-rw-r--r-- | elpa/dash-20200524.1947/dash.el | 3072 | ||||
-rw-r--r-- | elpa/dash-20200524.1947/dash.info | 3410 | ||||
-rw-r--r-- | elpa/dash-20200524.1947/dir | 18 |
5 files changed, 6535 insertions, 0 deletions
diff --git a/elpa/dash-20200524.1947/dash-autoloads.el b/elpa/dash-20200524.1947/dash-autoloads.el new file mode 100644 index 0000000..c5e7902 --- /dev/null +++ b/elpa/dash-20200524.1947/dash-autoloads.el @@ -0,0 +1,26 @@ +;;; dash-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "dash" "dash.el" (0 0 0 0)) +;;; Generated autoloads from dash.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dash" '("dash-" "-keep" "-butlast" "-non" "-only-some" "-zip" "-e" "->" "-a" "-gr" "-when-let" "-d" "-l" "-s" "-p" "-r" "-m" "-i" "-f" "-u" "-value-to-list" "-t" "--" "-c" "!cons" "!cdr"))) + +;;;*** + +;;;### (autoloads nil nil ("dash-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; dash-autoloads.el ends here diff --git a/elpa/dash-20200524.1947/dash-pkg.el b/elpa/dash-20200524.1947/dash-pkg.el new file mode 100644 index 0000000..08d8982 --- /dev/null +++ b/elpa/dash-20200524.1947/dash-pkg.el @@ -0,0 +1,9 @@ +(define-package "dash" "20200524.1947" "A modern list library for Emacs" 'nil :commit "732d92eac56023a4fb4a5dc3d9d4e274ebf44bf9" :keywords + '("lists") + :authors + '(("Magnar Sveen" . "magnars@gmail.com")) + :maintainer + '("Magnar Sveen" . "magnars@gmail.com")) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/dash-20200524.1947/dash.el b/elpa/dash-20200524.1947/dash.el new file mode 100644 index 0000000..1fc2ec8 --- /dev/null +++ b/elpa/dash-20200524.1947/dash.el @@ -0,0 +1,3072 @@ +;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2016 Free Software Foundation, Inc. + +;; Author: Magnar Sveen <magnars@gmail.com> +;; Version: 2.17.0 +;; Keywords: lists + +;; This program 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 of the License, or +;; (at your option) any later version. + +;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; A modern list api for Emacs. +;; +;; See documentation on https://github.com/magnars/dash.el#functions +;; +;; **Please note** The lexical binding in this file is not utilised at the +;; moment. We will take full advantage of lexical binding in an upcoming 3.0 +;; release of Dash. In the meantime, we've added the pragma to avoid a bug that +;; you can read more about in https://github.com/magnars/dash.el/issues/130. +;; + +;;; Code: + +;; TODO: `gv' was introduced in Emacs 24.3, so remove this and all +;; calls to `defsetf' when support for earlier versions is dropped. +(eval-when-compile + (unless (fboundp 'gv-define-setter) + (require 'cl))) + +(defgroup dash () + "Customize group for dash.el" + :group 'lisp + :prefix "dash-") + +(defun dash--enable-fontlock (symbol value) + (when value + (dash-enable-font-lock)) + (set-default symbol value)) + +(defcustom dash-enable-fontlock nil + "If non-nil, enable fontification of dash functions, macros and +special values." + :type 'boolean + :set 'dash--enable-fontlock + :group 'dash) + +(defmacro !cons (car cdr) + "Destructive: Set CDR to the cons of CAR and CDR." + `(setq ,cdr (cons ,car ,cdr))) + +(defmacro !cdr (list) + "Destructive: Set LIST to the cdr of LIST." + `(setq ,list (cdr ,list))) + +(defmacro --each (list &rest body) + "Anaphoric form of `-each'." + (declare (debug (form body)) + (indent 1)) + (let ((l (make-symbol "list"))) + `(let ((,l ,list) + (it-index 0)) + (while ,l + (let ((it (car ,l))) + ,@body) + (setq it-index (1+ it-index)) + (!cdr ,l))))) + +(defmacro -doto (eval-initial-value &rest forms) + "Eval a form, then insert that form as the 2nd argument to other forms. +The EVAL-INITIAL-VALUE form is evaluated once. Its result is +passed to FORMS, which are then evaluated sequentially. Returns +the target form." + (declare (indent 1)) + (let ((retval (make-symbol "value"))) + `(let ((,retval ,eval-initial-value)) + ,@(mapcar (lambda (form) + (if (sequencep form) + `(,(-first-item form) ,retval ,@(cdr form)) + `(funcall form ,retval))) + forms) + ,retval))) + +(defmacro --doto (eval-initial-value &rest forms) + "Anaphoric form of `-doto'. +Note: `it' is not required in each form." + (declare (indent 1)) + `(let ((it ,eval-initial-value)) + ,@forms + it)) + +(defun -each (list fn) + "Call FN with every item in LIST. Return nil, used for side-effects only." + (--each list (funcall fn it))) + +(put '-each 'lisp-indent-function 1) + +(defalias '--each-indexed '--each) + +(defun -each-indexed (list fn) + "Call (FN index item) for each item in LIST. + +In the anaphoric form `--each-indexed', the index is exposed as symbol `it-index'. + +See also: `-map-indexed'." + (--each list (funcall fn it-index it))) +(put '-each-indexed 'lisp-indent-function 1) + +(defmacro --each-while (list pred &rest body) + "Anaphoric form of `-each-while'." + (declare (debug (form form body)) + (indent 2)) + (let ((l (make-symbol "list")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,c t) + (it-index 0)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) (setq ,c nil) ,@body)) + (setq it-index (1+ it-index)) + (!cdr ,l))))) + +(defun -each-while (list pred fn) + "Call FN with every item in LIST while (PRED item) is non-nil. +Return nil, used for side-effects only." + (--each-while list (funcall pred it) (funcall fn it))) + +(put '-each-while 'lisp-indent-function 2) + +(defmacro --each-r (list &rest body) + "Anaphoric form of `-each-r'." + (declare (debug (form body)) + (indent 1)) + (let ((v (make-symbol "vector"))) + ;; Implementation note: building vector is considerably faster + ;; than building a reversed list (vector takes less memory, so + ;; there is less GC), plus length comes naturally. In-place + ;; 'nreverse' would be faster still, but BODY would be able to see + ;; that, even if modification was reversed before we return. + `(let* ((,v (vconcat ,list)) + (it-index (length ,v)) + it) + (while (> it-index 0) + (setq it-index (1- it-index)) + (setq it (aref ,v it-index)) + ,@body)))) + +(defun -each-r (list fn) + "Call FN with every item in LIST in reversed order. + Return nil, used for side-effects only." + (--each-r list (funcall fn it))) + +(defmacro --each-r-while (list pred &rest body) + "Anaphoric form of `-each-r-while'." + (declare (debug (form form body)) + (indent 2)) + (let ((v (make-symbol "vector"))) + `(let* ((,v (vconcat ,list)) + (it-index (length ,v)) + it) + (while (> it-index 0) + (setq it-index (1- it-index)) + (setq it (aref ,v it-index)) + (if (not ,pred) + (setq it-index -1) + ,@body))))) + +(defun -each-r-while (list pred fn) + "Call FN with every item in reversed LIST while (PRED item) is non-nil. +Return nil, used for side-effects only." + (--each-r-while list (funcall pred it) (funcall fn it))) + +(defmacro --dotimes (num &rest body) + "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1." + (declare (debug (form body)) + (indent 1)) + (let ((n (make-symbol "num"))) + `(let ((,n ,num) + (it 0)) + (while (< it ,n) + ,@body + (setq it (1+ it)))))) + +(defun -dotimes (num fn) + "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1." + (--dotimes num (funcall fn it))) + +(put '-dotimes 'lisp-indent-function 1) + +(defun -map (fn list) + "Return a new list consisting of the result of applying FN to the items in LIST." + (mapcar fn list)) + +(defmacro --map (form list) + "Anaphoric form of `-map'." + (declare (debug (form form))) + `(mapcar (lambda (it) ,form) ,list)) + +(defmacro --reduce-from (form initial-value list) + "Anaphoric form of `-reduce-from'." + (declare (debug (form form form))) + `(let ((acc ,initial-value)) + (--each ,list (setq acc ,form)) + acc)) + +(defun -reduce-from (fn initial-value list) + "Return the result of applying FN to INITIAL-VALUE and the +first item in LIST, then applying FN to that result and the 2nd +item, etc. If LIST contains no items, return INITIAL-VALUE and +do not call FN. + +In the anaphoric form `--reduce-from', the accumulated value is +exposed as symbol `acc'. + +See also: `-reduce', `-reduce-r'" + (--reduce-from (funcall fn acc it) initial-value list)) + +(defmacro --reduce (form list) + "Anaphoric form of `-reduce'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reduce-from ,form (car ,lv) (cdr ,lv)) + (let (acc it) ,form))))) + +(defun -reduce (fn list) + "Return the result of applying FN to the first 2 items in LIST, +then applying FN to that result and the 3rd item, etc. If LIST +contains no items, return the result of calling FN with no +arguments. If LIST contains a single item, return that item +and do not call FN. + +In the anaphoric form `--reduce', the accumulated value is +exposed as symbol `acc'. + +See also: `-reduce-from', `-reduce-r'" + (if list + (-reduce-from fn (car list) (cdr list)) + (funcall fn))) + +(defmacro --reduce-r-from (form initial-value list) + "Anaphoric version of `-reduce-r-from'." + (declare (debug (form form form))) + `(--reduce-from ,form ,initial-value (reverse ,list))) + +(defun -reduce-r-from (fn initial-value list) + "Replace conses with FN, nil with INITIAL-VALUE and evaluate +the resulting expression. If LIST is empty, INITIAL-VALUE is +returned and FN is not called. + +Note: this function works the same as `-reduce-from' but the +operation associates from right instead of from left. + +See also: `-reduce-r', `-reduce'" + (--reduce-r-from (funcall fn it acc) initial-value list)) + +(defmacro --reduce-r (form list) + "Anaphoric version of `-reduce-r'." + (declare (debug (form form))) + `(--reduce ,form (reverse ,list))) + +(defun -reduce-r (fn list) + "Replace conses with FN and evaluate the resulting expression. +The final nil is ignored. If LIST contains no items, return the +result of calling FN with no arguments. If LIST contains a single +item, return that item and do not call FN. + +The first argument of FN is the new item, the second is the +accumulated value. + +Note: this function works the same as `-reduce' but the operation +associates from right instead of from left. + +See also: `-reduce-r-from', `-reduce'" + (if list + (--reduce-r (funcall fn it acc) list) + (funcall fn))) + +(defun -reductions-from (fn init list) + "Return a list of the intermediate values of the reduction. + +See `-reduce-from' for explanation of the arguments. + +See also: `-reductions', `-reductions-r', `-reduce-r'" + (nreverse (--reduce-from (cons (funcall fn (car acc) it) acc) (list init) list))) + +(defun -reductions (fn list) + "Return a list of the intermediate values of the reduction. + +See `-reduce' for explanation of the arguments. + +See also: `-reductions-from', `-reductions-r', `-reduce-r'" + (and list (-reductions-from fn (car list) (cdr list)))) + +(defun -reductions-r-from (fn init list) + "Return a list of the intermediate values of the reduction. + +See `-reduce-r-from' for explanation of the arguments. + +See also: `-reductions-r', `-reductions', `-reduce'" + (--reduce-r-from (cons (funcall fn it (car acc)) acc) (list init) list)) + +(defun -reductions-r (fn list) + "Return a list of the intermediate values of the reduction. + +See `-reduce-r' for explanation of the arguments. + +See also: `-reductions-r-from', `-reductions', `-reduce'" + (when list + (let ((rev (reverse list))) + (--reduce-from (cons (funcall fn it (car acc)) acc) + (list (car rev)) + (cdr rev))))) + +(defmacro --filter (form list) + "Anaphoric form of `-filter'. + +See also: `--remove'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (when ,form (!cons it ,r))) + (nreverse ,r)))) + +(defun -filter (pred list) + "Return a new list of the items in LIST for which PRED returns a non-nil value. + +Alias: `-select' + +See also: `-keep', `-remove'." + (--filter (funcall pred it) list)) + +(defalias '-select '-filter) +(defalias '--select '--filter) + +(defmacro --remove (form list) + "Anaphoric form of `-remove'. + +See also `--filter'." + (declare (debug (form form))) + `(--filter (not ,form) ,list)) + +(defun -remove (pred list) + "Return a new list of the items in LIST for which PRED returns nil. + +Alias: `-reject' + +See also: `-filter'." + (--remove (funcall pred it) list)) + +(defalias '-reject '-remove) +(defalias '--reject '--remove) + +(defun -remove-first (pred list) + "Return a new list with the first item matching PRED removed. + +Alias: `-reject-first' + +See also: `-remove', `-map-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cdr list)) + (nreverse front)))) + +(defmacro --remove-first (form list) + "Anaphoric form of `-remove-first'." + (declare (debug (form form))) + `(-remove-first (lambda (it) ,form) ,list)) + +(defalias '-reject-first '-remove-first) +(defalias '--reject-first '--remove-first) + +(defun -remove-last (pred list) + "Return a new list with the last item matching PRED removed. + +Alias: `-reject-last' + +See also: `-remove', `-map-last'" + (nreverse (-remove-first pred (reverse list)))) + +(defmacro --remove-last (form list) + "Anaphoric form of `-remove-last'." + (declare (debug (form form))) + `(-remove-last (lambda (it) ,form) ,list)) + +(defalias '-reject-last '-remove-last) +(defalias '--reject-last '--remove-last) + +(defun -remove-item (item list) + "Remove all occurrences of ITEM from LIST. + +Comparison is done with `equal'." + (declare (pure t) (side-effect-free t)) + (--remove (equal it item) list)) + +(defmacro --keep (form list) + "Anaphoric form of `-keep'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (m (make-symbol "mapped"))) + `(let (,r) + (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r)))) + (nreverse ,r)))) + +(defun -keep (fn list) + "Return a new list of the non-nil results of applying FN to the items in LIST. + +If you want to select the original items satisfying a predicate use `-filter'." + (--keep (funcall fn it) list)) + +(defun -non-nil (list) + "Return all non-nil elements of LIST." + (declare (pure t) (side-effect-free t)) + (-remove 'null list)) + +(defmacro --map-indexed (form list) + "Anaphoric form of `-map-indexed'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list + (!cons ,form ,r)) + (nreverse ,r)))) + +(defun -map-indexed (fn list) + "Return a new list consisting of the result of (FN index item) for each item in LIST. + +In the anaphoric form `--map-indexed', the index is exposed as symbol `it-index'. + +See also: `-each-indexed'." + (--map-indexed (funcall fn it-index it) list)) + +(defmacro --map-when (pred rep list) + "Anaphoric form of `-map-when'." + (declare (debug (form form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (!cons (if ,pred ,rep it) ,r)) + (nreverse ,r)))) + +(defun -map-when (pred rep list) + "Return a new list where the elements in LIST that do not match the PRED function +are unchanged, and where the elements in LIST that do match the PRED function are mapped +through the REP function. + +Alias: `-replace-where' + +See also: `-update-at'" + (--map-when (funcall pred it) (funcall rep it) list)) + +(defalias '-replace-where '-map-when) +(defalias '--replace-where '--map-when) + +(defun -map-first (pred rep list) + "Replace first item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list))) + (nreverse front)))) + +(defmacro --map-first (pred rep list) + "Anaphoric form of `-map-first'." + `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -map-last (pred rep list) + "Replace last item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-last'" + (nreverse (-map-first pred rep (reverse list)))) + +(defmacro --map-last (pred rep list) + "Anaphoric form of `-map-last'." + `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -replace (old new list) + "Replace all OLD items in LIST with NEW. + +Elements are compared using `equal'. + +See also: `-replace-at'" + (declare (pure t) (side-effect-free t)) + (--map-when (equal it old) new list)) + +(defun -replace-first (old new list) + "Replace the first occurrence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-first'" + (declare (pure t) (side-effect-free t)) + (--map-first (equal old it) new list)) + +(defun -replace-last (old new list) + "Replace the last occurrence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-last'" + (declare (pure t) (side-effect-free t)) + (--map-last (equal old it) new list)) + +(defmacro --mapcat (form list) + "Anaphoric form of `-mapcat'." + (declare (debug (form form))) + `(apply 'append (--map ,form ,list))) + +(defun -mapcat (fn list) + "Return the concatenation of the result of mapping FN over LIST. +Thus function FN should return a list." + (--mapcat (funcall fn it) list)) + +(defun -flatten (l) + "Take a nested list L and return its contents as a single, flat list. + +Note that because `nil' represents a list of zero elements (an +empty list), any mention of nil in L will disappear after +flattening. If you need to preserve nils, consider `-flatten-n' +or map them to some unique symbol and then map them back. + +Conses of two atoms are considered \"terminals\", that is, they +aren't flattened further. + +See also: `-flatten-n'" + (declare (pure t) (side-effect-free t)) + (if (and (listp l) (listp (cdr l))) + (-mapcat '-flatten l) + (list l))) + +(defmacro --iterate (form init n) + "Anaphoric version of `-iterate'." + (declare (debug (form form form))) + `(-iterate (lambda (it) ,form) ,init ,n)) + +(defun -flatten-n (num list) + "Flatten NUM levels of a nested LIST. + +See also: `-flatten'" + (declare (pure t) (side-effect-free t)) + (-last-item (--iterate (--mapcat (-list it) it) list (1+ num)))) + +(defun -concat (&rest lists) + "Return a new list with the concatenation of the elements in the supplied LISTS." + (declare (pure t) (side-effect-free t)) + (apply 'append lists)) + +(defalias '-copy 'copy-sequence + "Create a shallow copy of LIST. + +\(fn LIST)") + +(defun -splice (pred fun list) + "Splice lists generated by FUN in place of elements matching PRED in LIST. + +FUN takes the element matching PRED as input. + +This function can be used as replacement for `,@' in case you +need to splice several lists at marked positions (for example +with keywords). + +See also: `-splice-list', `-insert-at'" + (let (r) + (--each list + (if (funcall pred it) + (let ((new (funcall fun it))) + (--each new (!cons it r))) + (!cons it r))) + (nreverse r))) + +(defmacro --splice (pred form list) + "Anaphoric form of `-splice'." + `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list)) + +(defun -splice-list (pred new-list list) + "Splice NEW-LIST in place of elements matching PRED in LIST. + +See also: `-splice', `-insert-at'" + (-splice pred (lambda (_) new-list) list)) + +(defmacro --splice-list (pred new-list list) + "Anaphoric form of `-splice-list'." + `(-splice-list (lambda (it) ,pred) ,new-list ,list)) + +(defun -cons* (&rest args) + "Make a new list from the elements of ARGS. + +The last 2 members of ARGS are used as the final cons of the +result so if the final member of ARGS is not a list the result is +a dotted list." + (declare (pure t) (side-effect-free t)) + (-reduce-r 'cons args)) + +(defun -snoc (list elem &rest elements) + "Append ELEM to the end of the list. + +This is like `cons', but operates on the end of list. + +If ELEMENTS is non nil, append these to the list as well." + (-concat list (list elem) elements)) + +(defmacro --first (form list) + "Anaphoric form of `-first'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not ,n) + (when ,form (setq ,n it))) + ,n))) + +(defun -first (pred list) + "Return the first x in LIST where (PRED x) is non-nil, else nil. + +To get the first item in the list no questions asked, use `car'. + +Alias: `-find'" + (--first (funcall pred it) list)) + +(defalias '-find '-first) +(defalias '--find '--first) + +(defmacro --some (form list) + "Anaphoric form of `-some'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not ,n) + (setq ,n ,form)) + ,n))) + +(defun -some (pred list) + "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil. + +Alias: `-any'" + (--some (funcall pred it) list)) + +(defalias '-any '-some) +(defalias '--any '--some) + +(defmacro --last (form list) + "Anaphoric form of `-last'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each ,list + (when ,form (setq ,n it))) + ,n))) + +(defun -last (pred list) + "Return the last x in LIST where (PRED x) is non-nil, else nil." + (--last (funcall pred it) list)) + +(defalias '-first-item 'car + "Return the first item of LIST, or nil on an empty list. + +See also: `-second-item', `-last-item'. + +\(fn LIST)") + +;; Ensure that calls to `-first-item' are compiled to a single opcode, +;; just like `car'. +(put '-first-item 'byte-opcode 'byte-car) +(put '-first-item 'byte-compile 'byte-compile-one-arg) + +(defalias '-second-item 'cadr + "Return the second item of LIST, or nil if LIST is too short. + +See also: `-third-item'. + +\(fn LIST)") + +(defalias '-third-item + (if (fboundp 'caddr) + #'caddr + (lambda (list) (car (cddr list)))) + "Return the third item of LIST, or nil if LIST is too short. + +See also: `-fourth-item'. + +\(fn LIST)") + +(defun -fourth-item (list) + "Return the fourth item of LIST, or nil if LIST is too short. + +See also: `-fifth-item'." + (declare (pure t) (side-effect-free t)) + (car (cdr (cdr (cdr list))))) + +(defun -fifth-item (list) + "Return the fifth item of LIST, or nil if LIST is too short. + +See also: `-last-item'." + (declare (pure t) (side-effect-free t)) + (car (cdr (cdr (cdr (cdr list)))))) + +(defun -last-item (list) + "Return the last item of LIST, or nil on an empty list." + (declare (pure t) (side-effect-free t)) + (car (last list))) + +;; Use `with-no-warnings' to suppress unbound `-last-item' or +;; undefined `gv--defsetter' warnings arising from both +;; `gv-define-setter' and `defsetf' in certain Emacs versions. +(with-no-warnings + (if (fboundp 'gv-define-setter) + (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val)) + (defsetf -last-item (x) (val) `(setcar (last ,x) ,val)))) + +(defun -butlast (list) + "Return a list of all items in list except for the last." + ;; no alias as we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list)) + +(defmacro --count (pred list) + "Anaphoric form of `-count'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let ((,r 0)) + (--each ,list (when ,pred (setq ,r (1+ ,r)))) + ,r))) + +(defun -count (pred list) + "Counts the number of items in LIST where (PRED item) is non-nil." + (--count (funcall pred it) list)) + +(defun ---truthy? (val) + (declare (pure t) (side-effect-free t)) + (not (null val))) + +(defmacro --any? (form list) + "Anaphoric form of `-any?'." + (declare (debug (form form))) + `(---truthy? (--some ,form ,list))) + +(defun -any? (pred list) + "Return t if (PRED x) is non-nil for any x in LIST, else nil. + +Alias: `-any-p', `-some?', `-some-p'" + (--any? (funcall pred it) list)) + +(defalias '-some? '-any?) +(defalias '--some? '--any?) +(defalias '-any-p '-any?) +(defalias '--any-p '--any?) +(defalias '-some-p '-any?) +(defalias '--some-p '--any?) + +(defmacro --all? (form list) + "Anaphoric form of `-all?'." + (declare (debug (form form))) + (let ((a (make-symbol "all"))) + `(let ((,a t)) + (--each-while ,list ,a (setq ,a ,form)) + (---truthy? ,a)))) + +(defun -all? (pred list) + "Return t if (PRED x) is non-nil for all x in LIST, else nil. + +Alias: `-all-p', `-every?', `-every-p'" + (--all? (funcall pred it) list)) + +(defalias '-every? '-all?) +(defalias '--every? '--all?) +(defalias '-all-p '-all?) +(defalias '--all-p '--all?) +(defalias '-every-p '-all?) +(defalias '--every-p '--all?) + +(defmacro --none? (form list) + "Anaphoric form of `-none?'." + (declare (debug (form form))) + `(--all? (not ,form) ,list)) + +(defun -none? (pred list) + "Return t if (PRED x) is nil for all x in LIST, else nil. + +Alias: `-none-p'" + (--none? (funcall pred it) list)) + +(defalias '-none-p '-none?) +(defalias '--none-p '--none?) + +(defmacro --only-some? (form list) + "Anaphoric form of `-only-some?'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each-while ,list (not (and ,y ,n)) + (if ,form (setq ,y t) (setq ,n t))) + (---truthy? (and ,y ,n))))) + +(defun -only-some? (pred list) + "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED. +Return `nil` both if all items match the predicate or if none of the items match the predicate. + +Alias: `-only-some-p'" + (--only-some? (funcall pred it) list)) + +(defalias '-only-some-p '-only-some?) +(defalias '--only-some-p '--only-some?) + +(defun -slice (list from &optional to step) + "Return copy of LIST, starting from index FROM to index TO. + +FROM or TO may be negative. These values are then interpreted +modulo the length of the list. + +If STEP is a number, only each STEPth item in the resulting +section is returned. Defaults to 1." + (declare (pure t) (side-effect-free t)) + (let ((length (length list)) + (new-list nil)) + ;; to defaults to the end of the list + (setq to (or to length)) + (setq step (or step 1)) + ;; handle negative indices + (when (< from 0) + (setq from (mod from length))) + (when (< to 0) + (setq to (mod to length))) + + ;; iterate through the list, keeping the elements we want + (--each-while list (< it-index to) + (when (and (>= it-index from) + (= (mod (- from it-index) step) 0)) + (push it new-list))) + (nreverse new-list))) + +(defun -take (n list) + "Return a new list of the first N items in LIST, or all items if there are fewer than N. + +See also: `-take-last'" + (declare (pure t) (side-effect-free t)) + (let (result) + (--dotimes n + (when list + (!cons (car list) result) + (!cdr list))) + (nreverse result))) + +(defun -take-last (n list) + "Return the last N items of LIST in order. + +See also: `-take'" + (declare (pure t) (side-effect-free t)) + (copy-sequence (last list n))) + +(defalias '-drop 'nthcdr + "Return the tail of LIST without the first N items. + +See also: `-drop-last' + +\(fn N LIST)") + +(defun -drop-last (n list) + "Remove the last N items of LIST and return a copy. + +See also: `-drop'" + ;; No alias because we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list n)) + +(defmacro --take-while (form list) + "Anaphoric form of `-take-while'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each-while ,list ,form (!cons it ,r)) + (nreverse ,r)))) + +(defun -take-while (pred list) + "Return a new list of successive items from LIST while (PRED item) returns a non-nil value." + (--take-while (funcall pred it) list)) + +(defmacro --drop-while (form list) + "Anaphoric form of `-drop-while'." + (declare (debug (form form))) + (let ((l (make-symbol "list"))) + `(let ((,l ,list)) + (while (and ,l (let ((it (car ,l))) ,form)) + (!cdr ,l)) + ,l))) + +(defun -drop-while (pred list) + "Return the tail of LIST starting from the first item for which (PRED item) returns nil." + (--drop-while (funcall pred it) list)) + +(defun -split-at (n list) + "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list." + (declare (pure t) (side-effect-free t)) + (let (result) + (--dotimes n + (when list + (!cons (car list) result) + (!cdr list))) + (list (nreverse result) list))) + +(defun -rotate (n list) + "Rotate LIST N places to the right. With N negative, rotate to the left. +The time complexity is O(n)." + (declare (pure t) (side-effect-free t)) + (when list + (let* ((len (length list)) + (n-mod-len (mod n len)) + (new-tail-len (- len n-mod-len))) + (append (-drop new-tail-len list) (-take new-tail-len list))))) + +(defun -insert-at (n x list) + "Return a list with X inserted into LIST at position N. + +See also: `-splice', `-splice-list'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cadr split-list))))) + +(defun -replace-at (n x list) + "Return a list with element at Nth position in LIST replaced with X. + +See also: `-replace'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cdr (cadr split-list)))))) + +(defun -update-at (n func list) + "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`. + +See also: `-map-when'" + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list)))))) + +(defmacro --update-at (n form list) + "Anaphoric version of `-update-at'." + (declare (debug (form form form))) + `(-update-at ,n (lambda (it) ,form) ,list)) + +(defun -remove-at (n list) + "Return a list with element at Nth position in LIST removed. + +See also: `-remove-at-indices', `-remove'" + (declare (pure t) (side-effect-free t)) + (-remove-at-indices (list n) list)) + +(defun -remove-at-indices (indices list) + "Return a list whose elements are elements from LIST without +elements selected as `(nth i list)` for all i +from INDICES. + +See also: `-remove-at', `-remove'" + (declare (pure t) (side-effect-free t)) + (let* ((indices (-sort '< indices)) + (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices)))) + r) + (--each diffs + (let ((split (-split-at it list))) + (!cons (car split) r) + (setq list (cdr (cadr split))))) + (!cons list r) + (apply '-concat (nreverse r)))) + +(defmacro --split-with (pred list) + "Anaphoric form of `-split-with'." + (declare (debug (form form))) + (let ((l (make-symbol "list")) + (r (make-symbol "result")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,r nil) + (,c t)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) + (setq ,c nil) + (!cons it ,r) + (!cdr ,l)))) + (list (nreverse ,r) ,l)))) + +(defun -split-with (pred list) + "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list." + (--split-with (funcall pred it) list)) + +(defmacro -split-on (item list) + "Split the LIST each time ITEM is found. + +Unlike `-partition-by', the ITEM is discarded from the results. +Empty lists are also removed from the result. + +Comparison is done by `equal'. + +See also `-split-when'" + (declare (debug (form form))) + `(-split-when (lambda (it) (equal it ,item)) ,list)) + +(defmacro --split-when (form list) + "Anaphoric version of `-split-when'." + (declare (debug (form form))) + `(-split-when (lambda (it) ,form) ,list)) + +(defun -split-when (fn list) + "Split the LIST on each element where FN returns non-nil. + +Unlike `-partition-by', the \"matched\" element is discarded from +the results. Empty lists are also removed from the result. + +This function can be thought of as a generalization of +`split-string'." + (let (r s) + (while list + (if (not (funcall fn (car list))) + (push (car list) s) + (when s (push (nreverse s) r)) + (setq s nil)) + (!cdr list)) + (when s (push (nreverse s) r)) + (nreverse r))) + +(defmacro --separate (form list) + "Anaphoric form of `-separate'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each ,list (if ,form (!cons it ,y) (!cons it ,n))) + (list (nreverse ,y) (nreverse ,n))))) + +(defun -separate (pred list) + "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list." + (--separate (funcall pred it) list)) + +(defun ---partition-all-in-steps-reversed (n step list) + "Private: Used by -partition-all-in-steps and -partition-in-steps." + (when (< step 1) + (error "Step must be a positive number, or you're looking at some juicy infinite loops.")) + (let ((result nil)) + (while list + (!cons (-take n list) result) + (setq list (-drop step list))) + result)) + +(defun -partition-all-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +The last groups may contain less than N items." + (declare (pure t) (side-effect-free t)) + (nreverse (---partition-all-in-steps-reversed n step list))) + +(defun -partition-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (let ((result (---partition-all-in-steps-reversed n step list))) + (while (and result (< (length (car result)) n)) + (!cdr result)) + (nreverse result))) + +(defun -partition-all (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +The last group may contain less than N items." + (declare (pure t) (side-effect-free t)) + (-partition-all-in-steps n n list)) + +(defun -partition (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (-partition-in-steps n n list)) + +(defmacro --partition-by (form list) + "Anaphoric form of `-partition-by'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (v (make-symbol "value")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,v ,form) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (unless (equal ,v ,n) + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,v ,n)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by (fn list) + "Apply FN to each item in LIST, splitting it each time FN returns a new value." + (--partition-by (funcall fn it) list)) + +(defmacro --partition-by-header (form list) + "Anaphoric form of `-partition-by-header'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (h (make-symbol "header-value")) + (b (make-symbol "seen-body?")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,h ,form) + (,b nil) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (if (equal ,h ,n) + (when ,b + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,b nil)) + (setq ,b t)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by-header (fn list) + "Apply FN to the first item in LIST. That is the header +value. Apply FN to each item in LIST, splitting it each time FN +returns the header value, but only after seeing at least one +other value (the body)." + (--partition-by-header (funcall fn it) list)) + +(defun -partition-after-pred (pred list) + "Partition directly after each time PRED is true on an element of LIST." + (when list + (let ((rest (-partition-after-pred pred + (cdr list)))) + (if (funcall pred (car list)) + ;;split after (car list) + (cons (list (car list)) + rest) + + ;;don't split after (car list) + (cons (cons (car list) + (car rest)) + (cdr rest)))))) + +(defun -partition-before-pred (pred list) + "Partition directly before each time PRED is true on an element of LIST." + (nreverse (-map #'reverse + (-partition-after-pred pred (reverse list))))) + +(defun -partition-after-item (item list) + "Partition directly after each time ITEM appears in LIST." + (-partition-after-pred (lambda (ele) (equal ele item)) + list)) + +(defun -partition-before-item (item list) + "Partition directly before each time ITEM appears in LIST." + (-partition-before-pred (lambda (ele) (equal ele item)) + list)) + +(defmacro --group-by (form list) + "Anaphoric form of `-group-by'." + (declare (debug t)) + (let ((n (make-symbol "n")) + (k (make-symbol "k")) + (grp (make-symbol "grp"))) + `(nreverse + (-map + (lambda (,n) + (cons (car ,n) + (nreverse (cdr ,n)))) + (--reduce-from + (let* ((,k (,@form)) + (,grp (assoc ,k acc))) + (if ,grp + (setcdr ,grp (cons it (cdr ,grp))) + (push + (list ,k it) + acc)) + acc) + nil ,list))))) + +(defun -group-by (fn list) + "Separate LIST into an alist whose keys are FN applied to the +elements of LIST. Keys are compared by `equal'." + (--group-by (funcall fn it) list)) + +(defun -interpose (sep list) + "Return a new list of all elements in LIST separated by SEP." + (declare (pure t) (side-effect-free t)) + (let (result) + (when list + (!cons (car list) result) + (!cdr list)) + (while list + (setq result (cons (car list) (cons sep result))) + (!cdr list)) + (nreverse result))) + +(defun -interleave (&rest lists) + "Return a new list of the first item in each list, then the second etc." + (declare (pure t) (side-effect-free t)) + (when lists + (let (result) + (while (-none? 'null lists) + (--each lists (!cons (car it) result)) + (setq lists (-map 'cdr lists))) + (nreverse result)))) + +(defmacro --zip-with (form list1 list2) + "Anaphoric form of `-zip-with'. + +The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'." + (declare (debug (form form form))) + (let ((r (make-symbol "result")) + (l1 (make-symbol "list1")) + (l2 (make-symbol "list2"))) + `(let ((,r nil) + (,l1 ,list1) + (,l2 ,list2)) + (while (and ,l1 ,l2) + (let ((it (car ,l1)) + (other (car ,l2))) + (!cons ,form ,r) + (!cdr ,l1) + (!cdr ,l2))) + (nreverse ,r)))) + +(defun -zip-with (fn list1 list2) + "Zip the two lists LIST1 and LIST2 using a function FN. This +function is applied pairwise taking as first argument element of +LIST1 and as second argument element of LIST2 at corresponding +position. + +The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it', +and the elements from LIST2 as symbol `other'." + (--zip-with (funcall fn it other) list1 list2)) + +(defun -zip-lists (&rest lists) + "Zip LISTS together. Group the head of each list, followed by the +second elements of each list, and so on. The lengths of the returned +groupings are equal to the length of the shortest input list. + +The return value is always list of lists, which is a difference +from `-zip-pair' which returns a cons-cell in case two input +lists are provided. + +See also: `-zip'" + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (-none? 'null lists) + (setq results (cons (mapcar 'car lists) results)) + (setq lists (mapcar 'cdr lists))) + (nreverse results)))) + +(defun -zip (&rest lists) + "Zip LISTS together. Group the head of each list, followed by the +second elements of each list, and so on. The lengths of the returned +groupings are equal to the length of the shortest input list. + +If two lists are provided as arguments, return the groupings as a list +of cons cells. Otherwise, return the groupings as a list of lists. + +Use `-zip-lists' if you need the return value to always be a list +of lists. + +Alias: `-zip-pair' + +See also: `-zip-lists'" + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (-none? 'null lists) + (setq results (cons (mapcar 'car lists) results)) + (setq lists (mapcar 'cdr lists))) + (setq results (nreverse results)) + (if (= (length lists) 2) + ;; to support backward compatibility, return + ;; a cons cell if two lists were provided + (--map (cons (car it) (cadr it)) results) + results)))) + +(defalias '-zip-pair '-zip) + +(defun -zip-fill (fill-value &rest lists) + "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The +lengths of the returned groupings are equal to the length of the +longest input list." + (declare (pure t) (side-effect-free t)) + (apply '-zip (apply '-pad (cons fill-value lists)))) + +(defun -unzip (lists) + "Unzip LISTS. + +This works just like `-zip' but takes a list of lists instead of +a variable number of arguments, such that + + (-unzip (-zip L1 L2 L3 ...)) + +is identity (given that the lists are the same length). + +Note in particular that calling this on a list of two lists will +return a list of cons-cells such that the above identity works. + +See also: `-zip'" + (apply '-zip lists)) + +(defun -cycle (list) + "Return an infinite copy of LIST that will cycle through the +elements and repeat from the beginning." + (declare (pure t) (side-effect-free t)) + (let ((newlist (-map 'identity list))) + (nconc newlist newlist))) + +(defun -pad (fill-value &rest lists) + "Appends FILL-VALUE to the end of each list in LISTS such that they +will all have the same length." + (let* ((annotations (-annotate 'length lists)) + (n (-max (-map 'car annotations)))) + (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations))) + +(defun -annotate (fn list) + "Return a list of cons cells where each cell is FN applied to each +element of LIST paired with the unmodified element of LIST." + (-zip (-map fn list) list)) + +(defmacro --annotate (form list) + "Anaphoric version of `-annotate'." + (declare (debug (form form))) + `(-annotate (lambda (it) ,form) ,list)) + +(defun dash--table-carry (lists restore-lists &optional re) + "Helper for `-table' and `-table-flat'. + +If a list overflows, carry to the right and reset the list." + (while (not (or (car lists) + (equal lists '(nil)))) + (setcar lists (car restore-lists)) + (pop (cadr lists)) + (!cdr lists) + (!cdr restore-lists) + (when re + (push (nreverse (car re)) (cadr re)) + (setcar re nil) + (!cdr re)))) + +(defun -table (fn &rest lists) + "Compute outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The dimension of the result is (length lists). + +See also: `-table-flat'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + (re (make-list (length lists) nil))) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item (car re)) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists re))) + (nreverse (car (last re))))) + +(defun -table-flat (fn &rest lists) + "Compute flat outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The results are flattened, ignoring the tensor structure +of the result. This is equivalent to calling: + + (-flatten-n (1- (length lists)) (apply \\='-table fn lists)) + +but the implementation here is much more efficient. + +See also: `-flatten-n', `-table'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + re) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item re) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists))) + (nreverse re))) + +(defun -partial (fn &rest args) + "Take a function FN and fewer than the normal arguments to FN, +and return a fn that takes a variable number of additional ARGS. +When called, the returned function calls FN with ARGS first and +then additional args." + (apply 'apply-partially fn args)) + +(defun -elem-index (elem list) + "Return the index of the first element in the given LIST which +is equal to the query element ELEM, or nil if there is no +such element." + (declare (pure t) (side-effect-free t)) + (car (-elem-indices elem list))) + +(defun -elem-indices (elem list) + "Return the indices of all elements in LIST equal to the query +element ELEM, in ascending order." + (declare (pure t) (side-effect-free t)) + (-find-indices (-partial 'equal elem) list)) + +(defun -find-indices (pred list) + "Return the indices of all elements in LIST satisfying the +predicate PRED, in ascending order." + (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list))) + +(defmacro --find-indices (form list) + "Anaphoric version of `-find-indices'." + (declare (debug (form form))) + `(-find-indices (lambda (it) ,form) ,list)) + +(defun -find-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +first element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-first'." + (car (-find-indices pred list))) + +(defmacro --find-index (form list) + "Anaphoric version of `-find-index'." + (declare (debug (form form))) + `(-find-index (lambda (it) ,form) ,list)) + +(defun -find-last-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +last element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-last'." + (-last-item (-find-indices pred list))) + +(defmacro --find-last-index (form list) + "Anaphoric version of `-find-last-index'." + `(-find-last-index (lambda (it) ,form) ,list)) + +(defun -select-by-indices (indices list) + "Return a list whose elements are elements from LIST selected +as `(nth i list)` for all i from INDICES." + (declare (pure t) (side-effect-free t)) + (let (r) + (--each indices + (!cons (nth it list) r)) + (nreverse r))) + +(defun -select-columns (columns table) + "Select COLUMNS from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +Each row is transformed such that only the specified COLUMNS are +selected. + +See also: `-select-column', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--map (-select-by-indices columns it) table)) + +(defun -select-column (column table) + "Select COLUMN from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +The single selected column is returned as a list. + +See also: `-select-columns', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--mapcat (-select-by-indices (list column) it) table)) + +(defmacro -> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the second item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +second item in second form, etc." + (declare (debug (form &rest [&or symbolp (sexp &rest form)]))) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,(car form) ,x ,@(cdr form)) + (list form x))) + (:else `(-> (-> ,x ,form) ,@more)))) + +(defmacro ->> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the last item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +last item in second form, etc." + (declare (debug ->)) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,@form ,x) + (list form x))) + (:else `(->> (->> ,x ,form) ,@more)))) + +(defmacro --> (x &rest forms) + "Starting with the value of X, thread each expression through FORMS. + +Insert X at the position signified by the symbol `it' in the first +form. If there are more forms, insert the first form at the position +signified by `it' in in second form, etc." + (declare (debug (form body))) + `(-as-> ,x it ,@forms)) + +(defmacro -as-> (value variable &rest forms) + "Starting with VALUE, thread VARIABLE through FORMS. + +In the first form, bind VARIABLE to VALUE. In the second form, bind +VARIABLE to the result of the first form, and so forth." + (declare (debug (form symbolp body))) + (if (null forms) + `,value + `(let ((,variable ,value)) + (-as-> ,(if (symbolp (car forms)) + (list (car forms) variable) + (car forms)) + ,variable + ,@(cdr forms))))) + +(defmacro -some-> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->) + (indent 1)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some-> (-when-let (,result ,x) + (-> ,result ,form)) + ,@more)))) + +(defmacro -some->> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->>'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->) + (indent 1)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some->> (-when-let (,result ,x) + (->> ,result ,form)) + ,@more)))) + +(defmacro -some--> (x &optional form &rest more) + "When expr in non-nil, thread it through the first form (via `-->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->) + (indent 1)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some--> (-when-let (,result ,x) + (--> ,result ,form)) + ,@more)))) + +(defun -grade-up (comparator list) + "Grade elements of LIST using COMPARATOR relation, yielding a +permutation vector such that applying this permutation to LIST +sorts it in ascending order." + ;; ugly hack to "fix" lack of lexical scope + (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other))))) + (->> (--map-indexed (cons it it-index) list) + (-sort comp) + (-map 'cdr)))) + +(defun -grade-down (comparator list) + "Grade elements of LIST using COMPARATOR relation, yielding a +permutation vector such that applying this permutation to LIST +sorts it in descending order." + ;; ugly hack to "fix" lack of lexical scope + (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it))))) + (->> (--map-indexed (cons it it-index) list) + (-sort comp) + (-map 'cdr)))) + +(defvar dash--source-counter 0 + "Monotonic counter for generated symbols.") + +(defun dash--match-make-source-symbol () + "Generate a new dash-source symbol. + +All returned symbols are guaranteed to be unique." + (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter)) + (setq dash--source-counter (1+ dash--source-counter)))) + +(defun dash--match-ignore-place-p (symbol) + "Return non-nil if SYMBOL is a symbol and starts with _." + (and (symbolp symbol) + (eq (aref (symbol-name symbol) 0) ?_))) + +(defun dash--match-cons-skip-cdr (skip-cdr source) + "Helper function generating idiomatic shifting code." + (cond + ((= skip-cdr 0) + `(pop ,source)) + (t + `(prog1 ,(dash--match-cons-get-car skip-cdr source) + (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source)))))) + +(defun dash--match-cons-get-car (skip-cdr source) + "Helper function generating idiomatic code to get nth car." + (cond + ((= skip-cdr 0) + `(car ,source)) + ((= skip-cdr 1) + `(cadr ,source)) + (t + `(nth ,skip-cdr ,source)))) + +(defun dash--match-cons-get-cdr (skip-cdr source) + "Helper function generating idiomatic code to get nth cdr." + (cond + ((= skip-cdr 0) + source) + ((= skip-cdr 1) + `(cdr ,source)) + (t + `(nthcdr ,skip-cdr ,source)))) + +(defun dash--match-cons (match-form source) + "Setup a cons matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol)) + (n 0) + (m match-form)) + (while (and (consp m) + (dash--match-ignore-place-p (car m))) + (setq n (1+ n)) (!cdr m)) + (cond + ;; when we only have one pattern in the list, we don't have to + ;; create a temporary binding (--dash-source--) for the source + ;; and just use the input directly + ((and (consp m) + (not (cdr m))) + (dash--match (car m) (dash--match-cons-get-car n source))) + ;; handle other special types + ((> n 0) + (dash--match m (dash--match-cons-get-cdr n source))) + ;; this is the only entry-point for dash--match-cons-1, that's + ;; why we can't simply use the above branch, it would produce + ;; infinite recursion + (t + (cons (list s source) (dash--match-cons-1 match-form s)))))) + +(defun dash--get-expand-function (type) + "Get expand function name for TYPE." + (intern-soft (format "dash-expand:%s" type))) + +(defun dash--match-cons-1 (match-form source &optional props) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a proper or improper list. Each element of +MATCH-FORM is either a symbol, which gets bound to the respective +value in source or another match form which gets destructured +recursively. + +If the cdr of last cons cell in the list is `nil', matching stops +there. + +SOURCE is a proper or improper list." + (let ((skip-cdr (or (plist-get props :skip-cdr) 0))) + (cond + ((consp match-form) + (cond + ((cdr match-form) + (cond + ((and (symbolp (car match-form)) + (functionp (dash--get-expand-function (car match-form)))) + (dash--match-kv (dash--match-kv-normalize-match-form match-form) (dash--match-cons-get-cdr skip-cdr source))) + ((dash--match-ignore-place-p (car match-form)) + (dash--match-cons-1 (cdr match-form) source + (plist-put props :skip-cdr (1+ skip-cdr)))) + (t + (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source)) + (dash--match-cons-1 (cdr match-form) source))))) + (t ;; Last matching place, no need for shift + (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source))))) + ((eq match-form nil) + nil) + (t ;; Handle improper lists. Last matching place, no need for shift + (dash--match match-form (dash--match-cons-get-cdr skip-cdr source)))))) + +(defun dash--vector-tail (seq start) + "Return the tail of SEQ starting at START." + (cond + ((vectorp seq) + (let* ((re-length (- (length seq) start)) + (re (make-vector re-length 0))) + (--dotimes re-length (aset re it (aref seq (+ it start)))) + re)) + ((stringp seq) + (substring seq start)))) + +(defun dash--match-vector (match-form source) + "Setup a vector matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern + ((= (length match-form) 1) + (dash--match (aref match-form 0) `(aref ,source 0))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-vector-1 match-form source)) + ;; don't bind `s' if we only have one sub-pattern which is not ignored + ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form)) + (ignored-places-n (length (-remove 'null ignored-places)))) + (when (= ignored-places-n (1- (length match-form))) + (let ((n (-find-index 'null ignored-places))) + (dash--match (aref match-form n) `(aref ,source ,n)))))) + (t + (cons (list s source) (dash--match-vector-1 match-form s)))))) + +(defun dash--match-vector-1 (match-form source) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a vector. Each element of MATCH-FORM is either a +symbol, which gets bound to the respective value in source or +another match form which gets destructured recursively. + +If second-from-last place in MATCH-FORM is the symbol &rest, the +next element of the MATCH-FORM is matched against the tail of +SOURCE, starting at index of the &rest symbol. This is +conceptually the same as the (head . tail) match for improper +lists, where dot plays the role of &rest. + +SOURCE is a vector. + +If the MATCH-FORM vector is shorter than SOURCE vector, only +the (length MATCH-FORM) places are bound, the rest of the SOURCE +is discarded." + (let ((i 0) + (l (length match-form)) + (re)) + (while (< i l) + (let ((m (aref match-form i))) + (push (cond + ((and (symbolp m) + (eq m '&rest)) + (prog1 (dash--match + (aref match-form (1+ i)) + `(dash--vector-tail ,source ,i)) + (setq i l))) + ((and (symbolp m) + ;; do not match symbols starting with _ + (not (eq (aref (symbol-name m) 0) ?_))) + (list (list m `(aref ,source ,i)))) + ((not (symbolp m)) + (dash--match m `(aref ,source ,i)))) + re) + (setq i (1+ i)))) + (-flatten-n 1 (nreverse re)))) + +(defun dash--match-kv-normalize-match-form (pattern) + "Normalize kv PATTERN. + +This method normalizes PATTERN to the format expected by +`dash--match-kv'. See `-let' for the specification." + (let ((normalized (list (car pattern))) + (skip nil) + (fill-placeholder (make-symbol "--dash-fill-placeholder--"))) + (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern))) + (lambda (pair) + (let ((current (car pair)) + (next (cdr pair))) + (if skip + (setq skip nil) + (if (or (eq fill-placeholder next) + (not (or (and (symbolp next) + (not (keywordp next)) + (not (eq next t)) + (not (eq next nil))) + (and (consp next) + (not (eq (car next) 'quote))) + (vectorp next)))) + (progn + (cond + ((keywordp current) + (push current normalized) + (push (intern (substring (symbol-name current) 1)) normalized)) + ((stringp current) + (push current normalized) + (push (intern current) normalized)) + ((and (consp current) + (eq (car current) 'quote)) + (push current normalized) + (push (cadr current) normalized)) + (t (error "-let: found key `%s' in kv destructuring but its pattern `%s' is invalid and can not be derived from the key" current next))) + (setq skip nil)) + (push current normalized) + (push next normalized) + (setq skip t)))))) + (nreverse normalized))) + +(defun dash--match-kv (match-form source) + "Setup a kv matching environment and call the real matcher. + +kv can be any key-value store, such as plist, alist or hash-table." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern (&type key val) + ((= (length match-form) 3) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + (t + (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form))))))) + +(defun dash-expand:&hash (key source) + "Generate extracting KEY from SOURCE for &hash destructuring." + `(gethash ,key ,source)) + +(defun dash-expand:&plist (key source) + "Generate extracting KEY from SOURCE for &plist destructuring." + `(plist-get ,source ,key)) + +(defun dash-expand:&alist (key source) + "Generate extracting KEY from SOURCE for &alist destructuring." + `(cdr (assoc ,key ,source))) + +(defun dash-expand:&hash? (key source) + "Generate extracting KEY from SOURCE for &hash? destructuring. +Similar to &hash but check whether the map is not nil." + (let ((src (make-symbol "src"))) + `(let ((,src ,source)) + (when ,src (gethash ,key ,src))))) + +(defalias 'dash-expand:&keys 'dash-expand:&plist) + +(defun dash--match-kv-1 (match-form source type) + "Match MATCH-FORM against SOURCE of type TYPE. + +MATCH-FORM is a proper list of the form (key1 place1 ... keyN +placeN). Each placeK is either a symbol, which gets bound to the +value of keyK retrieved from the key-value store, or another +match form which gets destructured recursively. + +SOURCE is a key-value store of type TYPE, which can be a plist, +an alist or a hash table. + +TYPE is a token specifying the type of the key-value store. +Valid values are &plist, &alist and &hash." + (-flatten-n 1 (-map + (lambda (kv) + (let* ((k (car kv)) + (v (cadr kv)) + (getter + (funcall (dash--get-expand-function type) k source))) + (cond + ((symbolp v) + (list (list v getter))) + (t (dash--match v getter))))) + (-partition 2 match-form)))) + +(defun dash--match-symbol (match-form source) + "Bind a symbol. + +This works just like `let', there is no destructuring." + (list (list match-form source))) + +(defun dash--match (match-form source) + "Match MATCH-FORM against SOURCE. + +This function tests the MATCH-FORM and dispatches to specific +matchers based on the type of the expression. + +Key-value stores are disambiguated by placing a token &plist, +&alist or &hash as a first item in the MATCH-FORM." + (cond + ((symbolp match-form) + (dash--match-symbol match-form source)) + ((consp match-form) + (cond + ;; Handle the "x &as" bindings first. + ((and (consp (cdr match-form)) + (symbolp (car match-form)) + (eq '&as (cadr match-form))) + (let ((s (car match-form))) + (cons (list s source) + (dash--match (cddr match-form) s)))) + ((functionp (dash--get-expand-function (car match-form))) + (dash--match-kv (dash--match-kv-normalize-match-form match-form) source)) + (t (dash--match-cons match-form source)))) + ((vectorp match-form) + ;; We support the &as binding in vectors too + (cond + ((and (> (length match-form) 2) + (symbolp (aref match-form 0)) + (eq '&as (aref match-form 1))) + (let ((s (aref match-form 0))) + (cons (list s source) + (dash--match (dash--vector-tail match-form 2) s)))) + (t (dash--match-vector match-form source)))))) + +(defun dash--normalize-let-varlist (varlist) + "Normalize VARLIST so that every binding is a list. + +`let' allows specifying a binding which is not a list but simply +the place which is then automatically bound to nil, such that all +three of the following are identical and evaluate to nil. + + (let (a) a) + (let ((a)) a) + (let ((a nil)) a) + +This function normalizes all of these to the last form." + (--map (if (consp it) it (list it nil)) varlist)) + +(defmacro -let* (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE structurally. SOURCE is +only evaluated once for each PATTERN. + +Each SOURCE can refer to the symbols already bound by this +VARLIST. This is useful if you want to destructure SOURCE +recursively but also want to name the intermediate structures. + +See `-let' for the list of all possible patterns." + (declare (debug ((&rest [&or (sexp form) sexp]) body)) + (indent 1)) + (let* ((varlist (dash--normalize-let-varlist varlist)) + (bindings (--mapcat (dash--match (car it) (cadr it)) varlist))) + `(let* ,bindings + ,@body))) + +(defmacro -let (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE \"structurally\". SOURCE +is only evaluated once for each PATTERN. Each PATTERN is matched +recursively, and can therefore contain sub-patterns which are +matched against corresponding sub-expressions of SOURCE. + +All the SOURCEs are evalled before any symbols are +bound (i.e. \"in parallel\"). + +If VARLIST only contains one (PATTERN SOURCE) element, you can +optionally specify it using a vector and discarding the +outer-most parens. Thus + + (-let ((PATTERN SOURCE)) ..) + +becomes + + (-let [PATTERN SOURCE] ..). + +`-let' uses a convention of not binding places (symbols) starting +with _ whenever it's possible. You can use this to skip over +entries you don't care about. However, this is not *always* +possible (as a result of implementation) and these symbols might +get bound to undefined values. + +Following is the overview of supported patterns. Remember that +patterns can be matched recursively, so every a, b, aK in the +following can be a matching construct and not necessarily a +symbol/variable. + +Symbol: + + a - bind the SOURCE to A. This is just like regular `let'. + +Conses and lists: + + (a) - bind `car' of cons/list to A + + (a . b) - bind car of cons to A and `cdr' to B + + (a b) - bind car of list to A and `cadr' to B + + (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ... + + (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST. + +Vectors: + + [a] - bind 0th element of a non-list sequence to A (works with + vectors, strings, bit arrays...) + + [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to + A1, 2nd to A2, ... + If the PATTERN is shorter than SOURCE, the values at + places not in PATTERN are ignored. + If the PATTERN is longer than SOURCE, an `error' is + thrown. + + [a1 a2 a3 ... &rest rest] - as above, but bind the rest of + the sequence to REST. This is + conceptually the same as improper list + matching (a1 a2 ... aN . rest) + +Key/value stores: + + (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE plist to aK. If the + value is not found, aK is nil. + Uses `plist-get' to fetch values. + + (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE alist to aK. If the + value is not found, aK is nil. + Uses `assoc' to fetch values. + + (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE hash table to aK. If the + value is not found, aK is nil. + Uses `gethash' to fetch values. + +Further, special keyword &keys supports \"inline\" matching of +plist-like key-value pairs, similarly to &keys keyword of +`cl-defun'. + + (a1 a2 ... aN &keys key1 b1 ... keyN bK) + +This binds N values from the list to a1 ... aN, then interprets +the cdr as a plist (see key/value matching above). + +A shorthand notation for kv-destructuring exists which allows the +patterns be optionally left out and derived from the key name in +the following fashion: + +- a key :foo is converted into `foo' pattern, +- a key 'bar is converted into `bar' pattern, +- a key \"baz\" is converted into `baz' pattern. + +That is, the entire value under the key is bound to the derived +variable without any further destructuring. + +This is possible only when the form following the key is not a +valid pattern (i.e. not a symbol, a cons cell or a vector). +Otherwise the matching proceeds as usual and in case of an +invalid spec fails with an error. + +Thus the patterns are normalized as follows: + + ;; derive all the missing patterns + (&plist :foo 'bar \"baz\") => (&plist :foo foo 'bar bar \"baz\" baz) + + ;; we can specify some but not others + (&plist :foo 'bar explicit-bar) => (&plist :foo foo 'bar explicit-bar) + + ;; nothing happens, we store :foo in x + (&plist :foo x) => (&plist :foo x) + + ;; nothing happens, we match recursively + (&plist :foo (a b c)) => (&plist :foo (a b c)) + +You can name the source using the syntax SYMBOL &as PATTERN. +This syntax works with lists (proper or improper), vectors and +all types of maps. + + (list &as a b c) (list 1 2 3) + +binds A to 1, B to 2, C to 3 and LIST to (1 2 3). + +Similarly: + + (bounds &as beg . end) (cons 1 2) + +binds BEG to 1, END to 2 and BOUNDS to (1 . 2). + + (items &as first . rest) (list 1 2 3) + +binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3) + + [vect &as _ b c] [1 2 3] + +binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual). + + (plist &as &plist :b b) (list :a 1 :b 2 :c 3) + +binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash. + +This is especially useful when we want to capture the result of a +computation and destructure at the same time. Consider the +form (function-returning-complex-structure) returning a list of +two vectors with two items each. We want to capture this entire +result and pass it to another computation, but at the same time +we want to get the second item from each vector. We can achieve +it with pattern + + (result &as [_ a] [_ b]) (function-returning-complex-structure) + +Note: Clojure programmers may know this feature as the \":as +binding\". The difference is that we put the &as at the front +because we need to support improper list binding." + (declare (debug ([&or (&rest [&or (sexp form) sexp]) + (vector [&rest [sexp form]])] + body)) + (indent 1)) + (if (vectorp varlist) + `(let* ,(dash--match (aref varlist 0) (aref varlist 1)) + ,@body) + (let* ((varlist (dash--normalize-let-varlist varlist)) + (inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist)) + (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs)))) + `(let ,inputs + (-let* ,new-varlist ,@body))))) + +(defmacro -lambda (match-form &rest body) + "Return a lambda which destructures its input as MATCH-FORM and executes BODY. + +Note that you have to enclose the MATCH-FORM in a pair of parens, +such that: + + (-lambda (x) body) + (-lambda (x y ...) body) + +has the usual semantics of `lambda'. Furthermore, these get +translated into normal lambda, so there is no performance +penalty. + +See `-let' for the description of destructuring mechanism." + (declare (doc-string 2) (indent defun) + (debug (&define sexp + [&optional stringp] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((not (consp match-form)) + (signal 'wrong-type-argument "match-form must be a list")) + ;; no destructuring, so just return regular lambda to make things faster + ((-all? 'symbolp match-form) + `(lambda ,match-form ,@body)) + (t + (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form))) + ;; TODO: because inputs to the lambda are evaluated only once, + ;; -let* need not to create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(lambda ,(--map (cadr it) inputs) + (-let* ,inputs ,@body)))))) + +(defmacro -setq (&rest forms) + "Bind each MATCH-FORM to the value of its VAL. + +MATCH-FORM destructuring is done according to the rules of `-let'. + +This macro allows you to bind multiple variables by destructuring +the value, so for example: + + (-setq (a b) x + (&plist :c c) plist) + +expands roughly speaking to the following code + + (setq a (car x) + b (cadr x) + c (plist-get plist :c)) + +Care is taken to only evaluate each VAL once so that in case of +multiple assignments it does not cause unexpected side effects. + +\(fn [MATCH-FORM VAL]...)" + (declare (debug (&rest sexp form)) + (indent 1)) + (when (= (mod (length forms) 2) 1) + (error "Odd number of arguments")) + (let* ((forms-and-sources + ;; First get all the necessary mappings with all the + ;; intermediate bindings. + (-map (lambda (x) (dash--match (car x) (cadr x))) + (-partition 2 forms))) + ;; To preserve the logic of dynamic scoping we must ensure + ;; that we `setq' the variables outside of the `let*' form + ;; which holds the destructured intermediate values. For + ;; this we generate for each variable a placeholder which is + ;; bound to (lexically) the result of the destructuring. + ;; Then outside of the helper `let*' form we bind all the + ;; original variables to their respective placeholders. + ;; TODO: There is a lot of room for possible optimization, + ;; for start playing with `special-variable-p' to eliminate + ;; unnecessary re-binding. + (variables-to-placeholders + (-mapcat + (lambda (bindings) + (-map + (lambda (binding) + (let ((var (car binding))) + (list var (make-symbol (concat "--dash-binding-" (symbol-name var) "--"))))) + (--filter (not (string-prefix-p "--" (symbol-name (car it)))) bindings))) + forms-and-sources))) + `(let ,(-map 'cadr variables-to-placeholders) + (let* ,(-flatten-n 1 forms-and-sources) + (setq ,@(-flatten (-map 'reverse variables-to-placeholders)))) + (setq ,@(-flatten variables-to-placeholders))))) + +(defmacro -if-let* (vars-vals then &rest else) + "If all VALS evaluate to true, bind them to their corresponding +VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list +of (VAR VAL) pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) form body)) + (indent 2)) + (->> vars-vals + (--mapcat (dash--match (car it) (cadr it))) + (--reduce-r-from + (let ((var (car it)) + (val (cadr it))) + `(let ((,var ,val)) + (if ,var ,acc ,@else))) + then))) + +(defmacro -if-let (var-val then &rest else) + "If VAL evaluates to non-nil, bind it to VAR and do THEN, +otherwise do ELSE. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) THEN &rest ELSE)" + (declare (debug ((sexp form) form body)) + (indent 2)) + `(-if-let* (,var-val) ,then ,@else)) + +(defmacro --if-let (val then &rest else) + "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN, +otherwise do ELSE." + (declare (debug (form form body)) + (indent 2)) + `(-if-let (it ,val) ,then ,@else)) + +(defmacro -when-let* (vars-vals &rest body) + "If all VALS evaluate to true, bind them to their corresponding +VARS and execute body. VARS-VALS should be a list of (VAR VAL) +pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) body)) + (indent 1)) + `(-if-let* ,vars-vals (progn ,@body))) + +(defmacro -when-let (var-val &rest body) + "If VAL evaluates to non-nil, bind it to VAR and execute body. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) &rest BODY)" + (declare (debug ((sexp form) body)) + (indent 1)) + `(-if-let ,var-val (progn ,@body))) + +(defmacro --when-let (val &rest body) + "If VAL evaluates to non-nil, bind it to symbol `it' and +execute body." + (declare (debug (form body)) + (indent 1)) + `(--if-let ,val (progn ,@body))) + +(defvar -compare-fn nil + "Tests for equality use this function or `equal' if this is nil. +It should only be set using dynamic scope with a let, like: + + (let ((-compare-fn #\\='=)) (-union numbers1 numbers2 numbers3)") + +(defun -distinct (list) + "Return a new list with all duplicates removed. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil. + +Alias: `-uniq'" + ;; Implementation note: The speedup gained from hash table lookup + ;; starts to outweigh its overhead for lists of length greater than + ;; 32. See discussion in PR #305. + (let* ((len (length list)) + (lut (and (> len 32) + ;; Check that `-compare-fn' is a valid hash-table + ;; lookup function or `nil'. + (memq -compare-fn '(nil equal eq eql)) + (make-hash-table :test (or -compare-fn #'equal) + :size len)))) + (if lut + (--filter (unless (gethash it lut) + (puthash it t lut)) + list) + (--each list (unless (-contains? lut it) (!cons it lut))) + (nreverse lut)))) + +(defalias '-uniq '-distinct) + +(defun -union (list list2) + "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + ;; We fall back to iteration implementation if the comparison + ;; function isn't one of `eq', `eql' or `equal'. + (let* ((result (reverse list)) + ;; TODO: get rid of this dynamic variable, pass it as an + ;; argument instead. + (-compare-fn (if (bound-and-true-p -compare-fn) + -compare-fn + 'equal))) + (if (memq -compare-fn '(eq eql equal)) + (let ((ht (make-hash-table :test -compare-fn))) + (--each list (puthash it t ht)) + (--each list2 (unless (gethash it ht) (!cons it result)))) + (--each list2 (unless (-contains? result it) (!cons it result)))) + (nreverse result))) + +(defun -intersection (list list2) + "Return a new list containing only the elements that are members of both LIST and LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (-contains? list2 it) list)) + +(defun -difference (list list2) + "Return a new list with only the members of LIST that are not in LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (not (-contains? list2 it)) list)) + +(defun -powerset (list) + "Return the power set of LIST." + (if (null list) '(()) + (let ((last (-powerset (cdr list)))) + (append (mapcar (lambda (x) (cons (car list) x)) last) + last)))) + +(defun -permutations (list) + "Return the permutations of LIST." + (if (null list) '(()) + (apply #'append + (mapcar (lambda (x) + (mapcar (lambda (perm) (cons x perm)) + (-permutations (remove x list)))) + list)))) + +(defun -inits (list) + "Return all prefixes of LIST." + (let ((res (list list))) + (setq list (reverse list)) + (while list + (push (reverse (!cdr list)) res)) + res)) + +(defun -tails (list) + "Return all suffixes of LIST" + (-reductions-r-from 'cons nil list)) + +(defun -common-prefix (&rest lists) + "Return the longest common prefix of LISTS." + (declare (pure t) (side-effect-free t)) + (--reduce (--take-while (and acc (equal (pop acc) it)) it) + lists)) + +(defun -common-suffix (&rest lists) + "Return the longest common suffix of LISTS." + (nreverse (apply #'-common-prefix (mapcar #'reverse lists)))) + +(defun -contains? (list element) + "Return non-nil if LIST contains ELEMENT. + +The test for equality is done with `equal', or with `-compare-fn' +if that's non-nil. + +Alias: `-contains-p'" + (not + (null + (cond + ((null -compare-fn) (member element list)) + ((eq -compare-fn 'eq) (memq element list)) + ((eq -compare-fn 'eql) (memql element list)) + (t + (let ((lst list)) + (while (and lst + (not (funcall -compare-fn element (car lst)))) + (setq lst (cdr lst))) + lst)))))) + +(defalias '-contains-p '-contains?) + +(defun -same-items? (list list2) + "Return true if LIST and LIST2 has the same items. + +The order of the elements in the lists does not matter. + +Alias: `-same-items-p'" + (let ((length-a (length list)) + (length-b (length list2))) + (and + (= length-a length-b) + (= length-a (length (-intersection list list2)))))) + +(defalias '-same-items-p '-same-items?) + +(defun -is-prefix? (prefix list) + "Return non-nil if PREFIX is prefix of LIST. + +Alias: `-is-prefix-p'" + (declare (pure t) (side-effect-free t)) + (--each-while list (equal (car prefix) it) + (!cdr prefix)) + (not prefix)) + +(defun -is-suffix? (suffix list) + "Return non-nil if SUFFIX is suffix of LIST. + +Alias: `-is-suffix-p'" + (declare (pure t) (side-effect-free t)) + (-is-prefix? (reverse suffix) (reverse list))) + +(defun -is-infix? (infix list) + "Return non-nil if INFIX is infix of LIST. + +This operation runs in O(n^2) time + +Alias: `-is-infix-p'" + (declare (pure t) (side-effect-free t)) + (let (done) + (while (and (not done) list) + (setq done (-is-prefix? infix list)) + (!cdr list)) + done)) + +(defalias '-is-prefix-p '-is-prefix?) +(defalias '-is-suffix-p '-is-suffix?) +(defalias '-is-infix-p '-is-infix?) + +(defun -sort (comparator list) + "Sort LIST, stably, comparing elements using COMPARATOR. +Return the sorted list. LIST is NOT modified by side effects. +COMPARATOR is called with two elements of LIST, and should return non-nil +if the first element should sort before the second." + (sort (copy-sequence list) comparator)) + +(defmacro --sort (form list) + "Anaphoric form of `-sort'." + (declare (debug (form form))) + `(-sort (lambda (it other) ,form) ,list)) + +(defun -list (&rest args) + "Return a list with ARGS. + +If first item of ARGS is already a list, simply return ARGS. If +not, return a list with ARGS as elements." + (declare (pure t) (side-effect-free t)) + (let ((arg (car args))) + (if (listp arg) arg args))) + +(defun -repeat (n x) + "Return a list with X repeated N times. +Return nil if N is less than 1." + (declare (pure t) (side-effect-free t)) + (let (ret) + (--dotimes n (!cons x ret)) + ret)) + +(defun -sum (list) + "Return the sum of LIST." + (declare (pure t) (side-effect-free t)) + (apply '+ list)) + +(defun -running-sum (list) + "Return a list with running sums of items in LIST. + +LIST must be non-empty." + (declare (pure t) (side-effect-free t)) + (unless (consp list) + (error "LIST must be non-empty")) + (-reductions '+ list)) + +(defun -product (list) + "Return the product of LIST." + (declare (pure t) (side-effect-free t)) + (apply '* list)) + +(defun -running-product (list) + "Return a list with running products of items in LIST. + +LIST must be non-empty." + (declare (pure t) (side-effect-free t)) + (unless (consp list) + (error "LIST must be non-empty")) + (-reductions '* list)) + +(defun -max (list) + "Return the largest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'max list)) + +(defun -min (list) + "Return the smallest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'min list)) + +(defun -max-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the greatest element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) it acc) list)) + +(defun -min-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the least element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) acc it) list)) + +(defmacro --max-by (form list) + "Anaphoric version of `-max-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (form form))) + `(-max-by (lambda (it other) ,form) ,list)) + +(defmacro --min-by (form list) + "Anaphoric version of `-min-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (form form))) + `(-min-by (lambda (it other) ,form) ,list)) + +(defun -iterate (fun init n) + "Return a list of iterated applications of FUN to INIT. + +This means a list of form: + + (init (fun init) (fun (fun init)) ...) + +N is the length of the returned list." + (if (= n 0) nil + (let ((r (list init))) + (--dotimes (1- n) + (push (funcall fun (car r)) r)) + (nreverse r)))) + +(defun -fix (fn list) + "Compute the (least) fixpoint of FN with initial input LIST. + +FN is called at least once, results are compared with `equal'." + (let ((re (funcall fn list))) + (while (not (equal list re)) + (setq list re) + (setq re (funcall fn re))) + re)) + +(defmacro --fix (form list) + "Anaphoric form of `-fix'." + `(-fix (lambda (it) ,form) ,list)) + +(defun -unfold (fun seed) + "Build a list from SEED using FUN. + +This is \"dual\" operation to `-reduce-r': while -reduce-r +consumes a list to produce a single value, `-unfold' takes a +seed value and builds a (potentially infinite!) list. + +FUN should return `nil' to stop the generating process, or a +cons (A . B), where A will be prepended to the result and B is +the new seed." + (let ((last (funcall fun seed)) r) + (while last + (push (car last) r) + (setq last (funcall fun (cdr last)))) + (nreverse r))) + +(defmacro --unfold (form seed) + "Anaphoric version of `-unfold'." + (declare (debug (form form))) + `(-unfold (lambda (it) ,form) ,seed)) + +(defun -cons-pair? (con) + "Return non-nil if CON is true cons pair. +That is (A . B) where B is not a list. + +Alias: `-cons-pair-p'" + (declare (pure t) (side-effect-free t)) + (and (listp con) + (not (listp (cdr con))))) + +(defalias '-cons-pair-p '-cons-pair?) + +(defun -cons-to-list (con) + "Convert a cons pair to a list with `car' and `cdr' of the pair respectively." + (declare (pure t) (side-effect-free t)) + (list (car con) (cdr con))) + +(defun -value-to-list (val) + "Convert a value to a list. + +If the value is a cons pair, make a list with two elements, `car' +and `cdr' of the pair respectively. + +If the value is anything else, wrap it in a list." + (declare (pure t) (side-effect-free t)) + (cond + ((-cons-pair? val) (-cons-to-list val)) + (t (list val)))) + +(defun -tree-mapreduce-from (fn folder init-value tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce-from' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce-from (form folder init-value tree) + "Anaphoric form of `-tree-mapreduce-from'." + (declare (debug (form form form form))) + `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree)) + +(defun -tree-mapreduce (fn folder tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce (form folder tree) + "Anaphoric form of `-tree-mapreduce'." + (declare (debug (form form form))) + `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree)) + +(defun -tree-map (fn tree) + "Apply FN to each element of TREE while preserving the tree structure." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (mapcar (lambda (x) (-tree-map fn x)) tree)) + (t (funcall fn tree)))) + +(defmacro --tree-map (form tree) + "Anaphoric form of `-tree-map'." + (declare (debug (form form))) + `(-tree-map (lambda (it) ,form) ,tree)) + +(defun -tree-reduce-from (fn init-value tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to INIT-VALUE and first element of the list, +then on this result and second element from the list etc. + +The initial value is ignored on cons pairs as they always contain +two elements." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree))) + (t tree))) + +(defmacro --tree-reduce-from (form init-value tree) + "Anaphoric form of `-tree-reduce-from'." + (declare (debug (form form form))) + `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree)) + +(defun -tree-reduce (fn tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to first element of the list and second +element, then on this result and third element from the list etc. + +See `-reduce-r' for how exactly are lists of zero or one element handled." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree))) + (t tree))) + +(defmacro --tree-reduce (form tree) + "Anaphoric form of `-tree-reduce'." + (declare (debug (form form))) + `(-tree-reduce (lambda (it acc) ,form) ,tree)) + +(defun -tree-map-nodes (pred fun tree) + "Call FUN on each node of TREE that satisfies PRED. + +If PRED returns nil, continue descending down this node. If PRED +returns non-nil, apply FUN to this node and do not descend +further." + (if (funcall pred tree) + (funcall fun tree) + (if (and (listp tree) + (not (-cons-pair? tree))) + (-map (lambda (x) (-tree-map-nodes pred fun x)) tree) + tree))) + +(defmacro --tree-map-nodes (pred form tree) + "Anaphoric form of `-tree-map-nodes'." + `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree)) + +(defun -tree-seq (branch children tree) + "Return a sequence of the nodes in TREE, in depth-first search order. + +BRANCH is a predicate of one argument that returns non-nil if the +passed argument is a branch, that is, a node that can have children. + +CHILDREN is a function of one argument that returns the children +of the passed branch node. + +Non-branch nodes are simply copied." + (cons tree + (when (funcall branch tree) + (-mapcat (lambda (x) (-tree-seq branch children x)) + (funcall children tree))))) + +(defmacro --tree-seq (branch children tree) + "Anaphoric form of `-tree-seq'." + `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree)) + +(defun -clone (list) + "Create a deep copy of LIST. +The new list has the same elements and structure but all cons are +replaced with new ones. This is useful when you need to clone a +structure such as plist or alist." + (declare (pure t) (side-effect-free t)) + (-tree-map 'identity list)) + +(defun dash-enable-font-lock () + "Add syntax highlighting to dash functions, macros and magic values." + (eval-after-load 'lisp-mode + '(progn + (let ((new-keywords '( + "!cons" + "!cdr" + "-each" + "--each" + "-each-indexed" + "--each-indexed" + "-each-while" + "--each-while" + "-doto" + "-dotimes" + "--dotimes" + "-map" + "--map" + "-reduce-from" + "--reduce-from" + "-reduce" + "--reduce" + "-reduce-r-from" + "--reduce-r-from" + "-reduce-r" + "--reduce-r" + "-reductions-from" + "-reductions-r-from" + "-reductions" + "-reductions-r" + "-filter" + "--filter" + "-select" + "--select" + "-remove" + "--remove" + "-reject" + "--reject" + "-remove-first" + "--remove-first" + "-reject-first" + "--reject-first" + "-remove-last" + "--remove-last" + "-reject-last" + "--reject-last" + "-remove-item" + "-non-nil" + "-keep" + "--keep" + "-map-indexed" + "--map-indexed" + "-splice" + "--splice" + "-splice-list" + "--splice-list" + "-map-when" + "--map-when" + "-replace-where" + "--replace-where" + "-map-first" + "--map-first" + "-map-last" + "--map-last" + "-replace" + "-replace-first" + "-replace-last" + "-flatten" + "-flatten-n" + "-concat" + "-mapcat" + "--mapcat" + "-copy" + "-cons*" + "-snoc" + "-first" + "--first" + "-find" + "--find" + "-some" + "--some" + "-any" + "--any" + "-last" + "--last" + "-first-item" + "-second-item" + "-third-item" + "-fourth-item" + "-fifth-item" + "-last-item" + "-butlast" + "-count" + "--count" + "-any?" + "--any?" + "-some?" + "--some?" + "-any-p" + "--any-p" + "-some-p" + "--some-p" + "-some->" + "-some->>" + "-some-->" + "-all?" + "-all-p" + "--all?" + "--all-p" + "-every?" + "--every?" + "-all-p" + "--all-p" + "-every-p" + "--every-p" + "-none?" + "--none?" + "-none-p" + "--none-p" + "-only-some?" + "--only-some?" + "-only-some-p" + "--only-some-p" + "-slice" + "-take" + "-drop" + "-drop-last" + "-take-last" + "-take-while" + "--take-while" + "-drop-while" + "--drop-while" + "-split-at" + "-rotate" + "-insert-at" + "-replace-at" + "-update-at" + "--update-at" + "-remove-at" + "-remove-at-indices" + "-split-with" + "--split-with" + "-split-on" + "-split-when" + "--split-when" + "-separate" + "--separate" + "-partition-all-in-steps" + "-partition-in-steps" + "-partition-all" + "-partition" + "-partition-after-item" + "-partition-after-pred" + "-partition-before-item" + "-partition-before-pred" + "-partition-by" + "--partition-by" + "-partition-by-header" + "--partition-by-header" + "-group-by" + "--group-by" + "-interpose" + "-interleave" + "-unzip" + "-zip-with" + "--zip-with" + "-zip" + "-zip-fill" + "-zip-lists" + "-zip-pair" + "-cycle" + "-pad" + "-annotate" + "--annotate" + "-table" + "-table-flat" + "-partial" + "-elem-index" + "-elem-indices" + "-find-indices" + "--find-indices" + "-find-index" + "--find-index" + "-find-last-index" + "--find-last-index" + "-select-by-indices" + "-select-columns" + "-select-column" + "-grade-up" + "-grade-down" + "->" + "->>" + "-->" + "-as->" + "-when-let" + "-when-let*" + "--when-let" + "-if-let" + "-if-let*" + "--if-let" + "-let*" + "-let" + "-lambda" + "-distinct" + "-uniq" + "-union" + "-intersection" + "-difference" + "-powerset" + "-permutations" + "-inits" + "-tails" + "-common-prefix" + "-common-suffix" + "-contains?" + "-contains-p" + "-same-items?" + "-same-items-p" + "-is-prefix-p" + "-is-prefix?" + "-is-suffix-p" + "-is-suffix?" + "-is-infix-p" + "-is-infix?" + "-sort" + "--sort" + "-list" + "-repeat" + "-sum" + "-running-sum" + "-product" + "-running-product" + "-max" + "-min" + "-max-by" + "--max-by" + "-min-by" + "--min-by" + "-iterate" + "--iterate" + "-fix" + "--fix" + "-unfold" + "--unfold" + "-cons-pair?" + "-cons-pair-p" + "-cons-to-list" + "-value-to-list" + "-tree-mapreduce-from" + "--tree-mapreduce-from" + "-tree-mapreduce" + "--tree-mapreduce" + "-tree-map" + "--tree-map" + "-tree-reduce-from" + "--tree-reduce-from" + "-tree-reduce" + "--tree-reduce" + "-tree-seq" + "--tree-seq" + "-tree-map-nodes" + "--tree-map-nodes" + "-clone" + "-rpartial" + "-juxt" + "-applify" + "-on" + "-flip" + "-const" + "-cut" + "-orfn" + "-andfn" + "-iteratefn" + "-fixfn" + "-prodfn" + )) + (special-variables '( + "it" + "it-index" + "acc" + "other" + ))) + (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>") + 1 font-lock-variable-name-face)) 'append) + (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>") + 1 font-lock-keyword-face)) 'append)) + (--each (buffer-list) + (with-current-buffer it + (when (and (eq major-mode 'emacs-lisp-mode) + (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-refresh-defaults))))))) + +(provide 'dash) +;;; dash.el ends here diff --git a/elpa/dash-20200524.1947/dash.info b/elpa/dash-20200524.1947/dash.info new file mode 100644 index 0000000..a88cea7 --- /dev/null +++ b/elpa/dash-20200524.1947/dash.info @@ -0,0 +1,3410 @@ +This is dash.info, produced by makeinfo version 6.5 from dash.texi. + +This manual is for ‘dash.el’ version 2.12.1. + + Copyright © 2012-2015 Magnar Sveen + + This program 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 of the + License, or (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Dash: (dash.info). A modern list library for GNU Emacs +END-INFO-DIR-ENTRY + + +File: dash.info, Node: Top, Next: Installation, Up: (dir) + +dash +**** + +This manual is for ‘dash.el’ version 2.12.1. + + Copyright © 2012-2015 Magnar Sveen + + This program 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 of the + License, or (at your option) any later version. + + This program 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 this program. If not, see + <http://www.gnu.org/licenses/>. + +* Menu: + +* Installation:: +* Functions:: +* Development:: +* Index:: + +— The Detailed Node Listing — + +Installation + +* Using in a package:: +* Syntax highlighting of dash functions:: + +Functions + +* Maps:: +* Sublist selection:: +* List to list:: +* Reductions:: +* Unfolding:: +* Predicates:: +* Partitioning:: +* Indexing:: +* Set operations:: +* Other list operations:: +* Tree operations:: +* Threading macros:: +* Binding:: +* Side-effects:: +* Destructive operations:: +* Function combinators:: + +Development + +* Contribute:: How to contribute +* Changes:: List of significant changes by version +* Contributors:: List of contributors + + +File: dash.info, Node: Installation, Next: Functions, Prev: Top, Up: Top + +1 Installation +************** + +It’s available on Melpa (https://melpa.org/); use ‘M-x package-install’: + +‘M-x package-install <RET> dash’ + Install the dash library. + +‘M-x package-install <RET> dash-functional’ + Optional, if you want the function combinators. + + Alternatively, you can just dump dash.el or dash-functional.el in +your load path somewhere. + +* Menu: + +* Using in a package:: +* Syntax highlighting of dash functions:: + + +File: dash.info, Node: Using in a package, Next: Syntax highlighting of dash functions, Up: Installation + +1.1 Using in a package +====================== + +Add this to the big comment block at the top: + + ;; Package-Requires: ((dash "2.12.1")) + +To get function combinators: + + ;; Package-Requires: ((dash "2.12.1") (dash-functional "1.2.0") (emacs "24")) + + +File: dash.info, Node: Syntax highlighting of dash functions, Prev: Using in a package, Up: Installation + +1.2 Syntax highlighting of dash functions +========================================= + +Font lock of dash functions in emacs lisp buffers is now optional. +Include this in your emacs settings to get syntax highlighting: + + (eval-after-load 'dash '(dash-enable-font-lock)) + + +File: dash.info, Node: Functions, Next: Development, Prev: Installation, Up: Top + +2 Functions +*********** + +This chapter contains reference documentation for the dash application +programming interface (API). All functions and constructs in the library +are prefixed with a dash (-). + + There are also anaphoric versions of functions where that makes +sense, prefixed with two dashes instead of one. + + For instance, while ‘-map’ takes a function to map over the list, one +can also use the anaphoric form with double dashes - which will then be +executed with ‘it’ exposed as the list item. Here’s an example: + + (-map (lambda (n) (* n n)) '(1 2 3 4)) ;; normal version + + (--map (* it it) '(1 2 3 4)) ;; anaphoric version + +Of course, the original can also be written like + + (defun square (n) (* n n)) + + (-map 'square '(1 2 3 4)) + +which demonstrates the usefulness of both versions. + +* Menu: + +* Maps:: +* Sublist selection:: +* List to list:: +* Reductions:: +* Unfolding:: +* Predicates:: +* Partitioning:: +* Indexing:: +* Set operations:: +* Other list operations:: +* Tree operations:: +* Threading macros:: +* Binding:: +* Side-effects:: +* Destructive operations:: +* Function combinators:: + + +File: dash.info, Node: Maps, Next: Sublist selection, Up: Functions + +2.1 Maps +======== + +Functions in this category take a transforming function, which is then +applied sequentially to each or selected elements of the input list. +The results are collected in order and returned as new list. + + -- Function: -map (fn list) + Return a new list consisting of the result of applying FN to the + items in LIST. + + (-map (lambda (num) (* num num)) '(1 2 3 4)) + ⇒ '(1 4 9 16) + (-map 'square '(1 2 3 4)) + ⇒ '(1 4 9 16) + (--map (* it it) '(1 2 3 4)) + ⇒ '(1 4 9 16) + + -- Function: -map-when (pred rep list) + Return a new list where the elements in LIST that do not match the + PRED function are unchanged, and where the elements in LIST that do + match the PRED function are mapped through the REP function. + + Alias: ‘-replace-where’ + + See also: ‘-update-at’ (*note -update-at::) + + (-map-when 'even? 'square '(1 2 3 4)) + ⇒ '(1 4 3 16) + (--map-when (> it 2) (* it it) '(1 2 3 4)) + ⇒ '(1 2 9 16) + (--map-when (= it 2) 17 '(1 2 3 4)) + ⇒ '(1 17 3 4) + + -- Function: -map-first (pred rep list) + Replace first item in LIST satisfying PRED with result of REP + called on this item. + + See also: ‘-map-when’ (*note -map-when::), ‘-replace-first’ (*note + -replace-first::) + + (-map-first 'even? 'square '(1 2 3 4)) + ⇒ '(1 4 3 4) + (--map-first (> it 2) (* it it) '(1 2 3 4)) + ⇒ '(1 2 9 4) + (--map-first (= it 2) 17 '(1 2 3 2)) + ⇒ '(1 17 3 2) + + -- Function: -map-last (pred rep list) + Replace last item in LIST satisfying PRED with result of REP called + on this item. + + See also: ‘-map-when’ (*note -map-when::), ‘-replace-last’ (*note + -replace-last::) + + (-map-last 'even? 'square '(1 2 3 4)) + ⇒ '(1 2 3 16) + (--map-last (> it 2) (* it it) '(1 2 3 4)) + ⇒ '(1 2 3 16) + (--map-last (= it 2) 17 '(1 2 3 2)) + ⇒ '(1 2 3 17) + + -- Function: -map-indexed (fn list) + Return a new list consisting of the result of (FN index item) for + each item in LIST. + + In the anaphoric form ‘--map-indexed’, the index is exposed as + symbol ‘it-index’. + + See also: ‘-each-indexed’ (*note -each-indexed::). + + (-map-indexed (lambda (index item) (- item index)) '(1 2 3 4)) + ⇒ '(1 1 1 1) + (--map-indexed (- it it-index) '(1 2 3 4)) + ⇒ '(1 1 1 1) + + -- Function: -annotate (fn list) + Return a list of cons cells where each cell is FN applied to each + element of LIST paired with the unmodified element of LIST. + + (-annotate '1+ '(1 2 3)) + ⇒ '((2 . 1) (3 . 2) (4 . 3)) + (-annotate 'length '(("h" "e" "l" "l" "o") ("hello" "world"))) + ⇒ '((5 "h" "e" "l" "l" "o") (2 "hello" "world")) + (--annotate (< 1 it) '(0 1 2 3)) + ⇒ '((nil . 0) (nil . 1) (t . 2) (t . 3)) + + -- Function: -splice (pred fun list) + Splice lists generated by FUN in place of elements matching PRED in + LIST. + + FUN takes the element matching PRED as input. + + This function can be used as replacement for ‘,@’ in case you need + to splice several lists at marked positions (for example with + keywords). + + See also: ‘-splice-list’ (*note -splice-list::), ‘-insert-at’ + (*note -insert-at::) + + (-splice 'even? (lambda (x) (list x x)) '(1 2 3 4)) + ⇒ '(1 2 2 3 4 4) + (--splice 't (list it it) '(1 2 3 4)) + ⇒ '(1 1 2 2 3 3 4 4) + (--splice (equal it :magic) '((list of) (magical) (code)) '((foo) (bar) :magic (baz))) + ⇒ '((foo) (bar) (list of) (magical) (code) (baz)) + + -- Function: -splice-list (pred new-list list) + Splice NEW-LIST in place of elements matching PRED in LIST. + + See also: ‘-splice’ (*note -splice::), ‘-insert-at’ (*note + -insert-at::) + + (-splice-list 'keywordp '(a b c) '(1 :foo 2)) + ⇒ '(1 a b c 2) + (-splice-list 'keywordp nil '(1 :foo 2)) + ⇒ '(1 2) + (--splice-list (keywordp it) '(a b c) '(1 :foo 2)) + ⇒ '(1 a b c 2) + + -- Function: -mapcat (fn list) + Return the concatenation of the result of mapping FN over LIST. + Thus function FN should return a list. + + (-mapcat 'list '(1 2 3)) + ⇒ '(1 2 3) + (-mapcat (lambda (item) (list 0 item)) '(1 2 3)) + ⇒ '(0 1 0 2 0 3) + (--mapcat (list 0 it) '(1 2 3)) + ⇒ '(0 1 0 2 0 3) + + -- Function: -copy (arg) + Create a shallow copy of LIST. + + (fn LIST) + + (-copy '(1 2 3)) + ⇒ '(1 2 3) + (let ((a '(1 2 3))) (eq a (-copy a))) + ⇒ nil + + +File: dash.info, Node: Sublist selection, Next: List to list, Prev: Maps, Up: Functions + +2.2 Sublist selection +===================== + +Functions returning a sublist of the original list. + + -- Function: -filter (pred list) + Return a new list of the items in LIST for which PRED returns a + non-nil value. + + Alias: ‘-select’ + + See also: ‘-keep’ (*note -keep::), ‘-remove’ (*note -remove::). + + (-filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) + ⇒ '(2 4) + (-filter 'even? '(1 2 3 4)) + ⇒ '(2 4) + (--filter (= 0 (% it 2)) '(1 2 3 4)) + ⇒ '(2 4) + + -- Function: -remove (pred list) + Return a new list of the items in LIST for which PRED returns nil. + + Alias: ‘-reject’ + + See also: ‘-filter’ (*note -filter::). + + (-remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) + ⇒ '(1 3) + (-remove 'even? '(1 2 3 4)) + ⇒ '(1 3) + (--remove (= 0 (% it 2)) '(1 2 3 4)) + ⇒ '(1 3) + + -- Function: -remove-first (pred list) + Return a new list with the first item matching PRED removed. + + Alias: ‘-reject-first’ + + See also: ‘-remove’ (*note -remove::), ‘-map-first’ (*note + -map-first::) + + (-remove-first 'even? '(1 3 5 4 7 8 10)) + ⇒ '(1 3 5 7 8 10) + (-remove-first 'stringp '(1 2 "first" "second" "third")) + ⇒ '(1 2 "second" "third") + (--remove-first (> it 3) '(1 2 3 4 5 6 7 8 9 10)) + ⇒ '(1 2 3 5 6 7 8 9 10) + + -- Function: -remove-last (pred list) + Return a new list with the last item matching PRED removed. + + Alias: ‘-reject-last’ + + See also: ‘-remove’ (*note -remove::), ‘-map-last’ (*note + -map-last::) + + (-remove-last 'even? '(1 3 5 4 7 8 10 11)) + ⇒ '(1 3 5 4 7 8 11) + (-remove-last 'stringp '(1 2 "last" "second" "third")) + ⇒ '(1 2 "last" "second") + (--remove-last (> it 3) '(1 2 3 4 5 6 7 8 9 10)) + ⇒ '(1 2 3 4 5 6 7 8 9) + + -- Function: -remove-item (item list) + Remove all occurrences of ITEM from LIST. + + Comparison is done with ‘equal’. + + (-remove-item 3 '(1 2 3 2 3 4 5 3)) + ⇒ '(1 2 2 4 5) + (-remove-item 'foo '(foo bar baz foo)) + ⇒ '(bar baz) + (-remove-item "bob" '("alice" "bob" "eve" "bob" "dave")) + ⇒ '("alice" "eve" "dave") + + -- Function: -non-nil (list) + Return all non-nil elements of LIST. + + (-non-nil '(1 nil 2 nil nil 3 4 nil 5 nil)) + ⇒ '(1 2 3 4 5) + + -- Function: -slice (list from &optional to step) + Return copy of LIST, starting from index FROM to index TO. + + FROM or TO may be negative. These values are then interpreted + modulo the length of the list. + + If STEP is a number, only each STEPth item in the resulting section + is returned. Defaults to 1. + + (-slice '(1 2 3 4 5) 1) + ⇒ '(2 3 4 5) + (-slice '(1 2 3 4 5) 0 3) + ⇒ '(1 2 3) + (-slice '(1 2 3 4 5 6 7 8 9) 1 -1 2) + ⇒ '(2 4 6 8) + + -- Function: -take (n list) + Return a new list of the first N items in LIST, or all items if + there are fewer than N. + + See also: ‘-take-last’ (*note -take-last::) + + (-take 3 '(1 2 3 4 5)) + ⇒ '(1 2 3) + (-take 17 '(1 2 3 4 5)) + ⇒ '(1 2 3 4 5) + + -- Function: -take-last (n list) + Return the last N items of LIST in order. + + See also: ‘-take’ (*note -take::) + + (-take-last 3 '(1 2 3 4 5)) + ⇒ '(3 4 5) + (-take-last 17 '(1 2 3 4 5)) + ⇒ '(1 2 3 4 5) + (-take-last 1 '(1 2 3 4 5)) + ⇒ '(5) + + -- Function: -drop (n list) + Return the tail of LIST without the first N items. + + See also: ‘-drop-last’ (*note -drop-last::) + + (fn N LIST) + + (-drop 3 '(1 2 3 4 5)) + ⇒ '(4 5) + (-drop 17 '(1 2 3 4 5)) + ⇒ '() + + -- Function: -drop-last (n list) + Remove the last N items of LIST and return a copy. + + See also: ‘-drop’ (*note -drop::) + + (-drop-last 3 '(1 2 3 4 5)) + ⇒ '(1 2) + (-drop-last 17 '(1 2 3 4 5)) + ⇒ '() + + -- Function: -take-while (pred list) + Return a new list of successive items from LIST while (PRED item) + returns a non-nil value. + + (-take-while 'even? '(1 2 3 4)) + ⇒ '() + (-take-while 'even? '(2 4 5 6)) + ⇒ '(2 4) + (--take-while (< it 4) '(1 2 3 4 3 2 1)) + ⇒ '(1 2 3) + + -- Function: -drop-while (pred list) + Return the tail of LIST starting from the first item for which + (PRED item) returns nil. + + (-drop-while 'even? '(1 2 3 4)) + ⇒ '(1 2 3 4) + (-drop-while 'even? '(2 4 5 6)) + ⇒ '(5 6) + (--drop-while (< it 4) '(1 2 3 4 3 2 1)) + ⇒ '(4 3 2 1) + + -- Function: -select-by-indices (indices list) + Return a list whose elements are elements from LIST selected as + ‘(nth i list)‘ for all i from INDICES. + + (-select-by-indices '(4 10 2 3 6) '("v" "e" "l" "o" "c" "i" "r" "a" "p" "t" "o" "r")) + ⇒ '("c" "o" "l" "o" "r") + (-select-by-indices '(2 1 0) '("a" "b" "c")) + ⇒ '("c" "b" "a") + (-select-by-indices '(0 1 2 0 1 3 3 1) '("f" "a" "r" "l")) + ⇒ '("f" "a" "r" "f" "a" "l" "l" "a") + + -- Function: -select-columns (columns table) + Select COLUMNS from TABLE. + + TABLE is a list of lists where each element represents one row. It + is assumed each row has the same length. + + Each row is transformed such that only the specified COLUMNS are + selected. + + See also: ‘-select-column’ (*note -select-column::), + ‘-select-by-indices’ (*note -select-by-indices::) + + (-select-columns '(0 2) '((1 2 3) (a b c) (:a :b :c))) + ⇒ '((1 3) (a c) (:a :c)) + (-select-columns '(1) '((1 2 3) (a b c) (:a :b :c))) + ⇒ '((2) (b) (:b)) + (-select-columns nil '((1 2 3) (a b c) (:a :b :c))) + ⇒ '(nil nil nil) + + -- Function: -select-column (column table) + Select COLUMN from TABLE. + + TABLE is a list of lists where each element represents one row. It + is assumed each row has the same length. + + The single selected column is returned as a list. + + See also: ‘-select-columns’ (*note -select-columns::), + ‘-select-by-indices’ (*note -select-by-indices::) + + (-select-column 1 '((1 2 3) (a b c) (:a :b :c))) + ⇒ '(2 b :b) + + +File: dash.info, Node: List to list, Next: Reductions, Prev: Sublist selection, Up: Functions + +2.3 List to list +================ + +Functions returning a modified copy of the input list. + + -- Function: -keep (fn list) + Return a new list of the non-nil results of applying FN to the + items in LIST. + + If you want to select the original items satisfying a predicate use + ‘-filter’ (*note -filter::). + + (-keep 'cdr '((1 2 3) (4 5) (6))) + ⇒ '((2 3) (5)) + (-keep (lambda (num) (when (> num 3) (* 10 num))) '(1 2 3 4 5 6)) + ⇒ '(40 50 60) + (--keep (when (> it 3) (* 10 it)) '(1 2 3 4 5 6)) + ⇒ '(40 50 60) + + -- Function: -concat (&rest lists) + Return a new list with the concatenation of the elements in the + supplied LISTS. + + (-concat '(1)) + ⇒ '(1) + (-concat '(1) '(2)) + ⇒ '(1 2) + (-concat '(1) '(2 3) '(4)) + ⇒ '(1 2 3 4) + + -- Function: -flatten (l) + Take a nested list L and return its contents as a single, flat + list. + + Note that because ‘nil’ represents a list of zero elements (an + empty list), any mention of nil in L will disappear after + flattening. If you need to preserve nils, consider ‘-flatten-n’ + (*note -flatten-n::) or map them to some unique symbol and then map + them back. + + Conses of two atoms are considered "terminals", that is, they + aren’t flattened further. + + See also: ‘-flatten-n’ (*note -flatten-n::) + + (-flatten '((1))) + ⇒ '(1) + (-flatten '((1 (2 3) (((4 (5))))))) + ⇒ '(1 2 3 4 5) + (-flatten '(1 2 (3 . 4))) + ⇒ '(1 2 (3 . 4)) + + -- Function: -flatten-n (num list) + Flatten NUM levels of a nested LIST. + + See also: ‘-flatten’ (*note -flatten::) + + (-flatten-n 1 '((1 2) ((3 4) ((5 6))))) + ⇒ '(1 2 (3 4) ((5 6))) + (-flatten-n 2 '((1 2) ((3 4) ((5 6))))) + ⇒ '(1 2 3 4 (5 6)) + (-flatten-n 3 '((1 2) ((3 4) ((5 6))))) + ⇒ '(1 2 3 4 5 6) + + -- Function: -replace (old new list) + Replace all OLD items in LIST with NEW. + + Elements are compared using ‘equal’. + + See also: ‘-replace-at’ (*note -replace-at::) + + (-replace 1 "1" '(1 2 3 4 3 2 1)) + ⇒ '("1" 2 3 4 3 2 "1") + (-replace "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo")) + ⇒ '("a" "nice" "bar" "sentence" "about" "bar") + (-replace 1 2 nil) + ⇒ nil + + -- Function: -replace-first (old new list) + Replace the first occurrence of OLD with NEW in LIST. + + Elements are compared using ‘equal’. + + See also: ‘-map-first’ (*note -map-first::) + + (-replace-first 1 "1" '(1 2 3 4 3 2 1)) + ⇒ '("1" 2 3 4 3 2 1) + (-replace-first "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo")) + ⇒ '("a" "nice" "bar" "sentence" "about" "foo") + (-replace-first 1 2 nil) + ⇒ nil + + -- Function: -replace-last (old new list) + Replace the last occurrence of OLD with NEW in LIST. + + Elements are compared using ‘equal’. + + See also: ‘-map-last’ (*note -map-last::) + + (-replace-last 1 "1" '(1 2 3 4 3 2 1)) + ⇒ '(1 2 3 4 3 2 "1") + (-replace-last "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo")) + ⇒ '("a" "nice" "foo" "sentence" "about" "bar") + (-replace-last 1 2 nil) + ⇒ nil + + -- Function: -insert-at (n x list) + Return a list with X inserted into LIST at position N. + + See also: ‘-splice’ (*note -splice::), ‘-splice-list’ (*note + -splice-list::) + + (-insert-at 1 'x '(a b c)) + ⇒ '(a x b c) + (-insert-at 12 'x '(a b c)) + ⇒ '(a b c x) + + -- Function: -replace-at (n x list) + Return a list with element at Nth position in LIST replaced with X. + + See also: ‘-replace’ (*note -replace::) + + (-replace-at 0 9 '(0 1 2 3 4 5)) + ⇒ '(9 1 2 3 4 5) + (-replace-at 1 9 '(0 1 2 3 4 5)) + ⇒ '(0 9 2 3 4 5) + (-replace-at 4 9 '(0 1 2 3 4 5)) + ⇒ '(0 1 2 3 9 5) + + -- Function: -update-at (n func list) + Return a list with element at Nth position in LIST replaced with + ‘(func (nth n list))‘. + + See also: ‘-map-when’ (*note -map-when::) + + (-update-at 0 (lambda (x) (+ x 9)) '(0 1 2 3 4 5)) + ⇒ '(9 1 2 3 4 5) + (-update-at 1 (lambda (x) (+ x 8)) '(0 1 2 3 4 5)) + ⇒ '(0 9 2 3 4 5) + (--update-at 2 (length it) '("foo" "bar" "baz" "quux")) + ⇒ '("foo" "bar" 3 "quux") + + -- Function: -remove-at (n list) + Return a list with element at Nth position in LIST removed. + + See also: ‘-remove-at-indices’ (*note -remove-at-indices::), + ‘-remove’ (*note -remove::) + + (-remove-at 0 '("0" "1" "2" "3" "4" "5")) + ⇒ '("1" "2" "3" "4" "5") + (-remove-at 1 '("0" "1" "2" "3" "4" "5")) + ⇒ '("0" "2" "3" "4" "5") + (-remove-at 2 '("0" "1" "2" "3" "4" "5")) + ⇒ '("0" "1" "3" "4" "5") + + -- Function: -remove-at-indices (indices list) + Return a list whose elements are elements from LIST without + elements selected as ‘(nth i list)‘ for all i from INDICES. + + See also: ‘-remove-at’ (*note -remove-at::), ‘-remove’ (*note + -remove::) + + (-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5")) + ⇒ '("1" "2" "3" "4" "5") + (-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5")) + ⇒ '("1" "3" "5") + (-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5")) + ⇒ '("1" "2" "3" "4") + + +File: dash.info, Node: Reductions, Next: Unfolding, Prev: List to list, Up: Functions + +2.4 Reductions +============== + +Functions reducing lists into single value. + + -- Function: -reduce-from (fn initial-value list) + Return the result of applying FN to INITIAL-VALUE and the first + item in LIST, then applying FN to that result and the 2nd item, + etc. If LIST contains no items, return INITIAL-VALUE and do not + call FN. + + In the anaphoric form ‘--reduce-from’, the accumulated value is + exposed as symbol ‘acc’. + + See also: ‘-reduce’ (*note -reduce::), ‘-reduce-r’ (*note + -reduce-r::) + + (-reduce-from '- 10 '(1 2 3)) + ⇒ 4 + (-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "10" '(1 2 3)) + ⇒ "(((10 - 1) - 2) - 3)" + (--reduce-from (concat acc " " it) "START" '("a" "b" "c")) + ⇒ "START a b c" + + -- Function: -reduce-r-from (fn initial-value list) + Replace conses with FN, nil with INITIAL-VALUE and evaluate the + resulting expression. If LIST is empty, INITIAL-VALUE is returned + and FN is not called. + + Note: this function works the same as ‘-reduce-from’ (*note + -reduce-from::) but the operation associates from right instead of + from left. + + See also: ‘-reduce-r’ (*note -reduce-r::), ‘-reduce’ (*note + -reduce::) + + (-reduce-r-from '- 10 '(1 2 3)) + ⇒ -8 + (-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "10" '(1 2 3)) + ⇒ "(1 - (2 - (3 - 10)))" + (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c")) + ⇒ "a b c END" + + -- Function: -reduce (fn list) + Return the result of applying FN to the first 2 items in LIST, then + applying FN to that result and the 3rd item, etc. If LIST contains + no items, return the result of calling FN with no arguments. If + LIST contains a single item, return that item and do not call FN. + + In the anaphoric form ‘--reduce’, the accumulated value is exposed + as symbol ‘acc’. + + See also: ‘-reduce-from’ (*note -reduce-from::), ‘-reduce-r’ (*note + -reduce-r::) + + (-reduce '- '(1 2 3 4)) + ⇒ -8 + (-reduce 'list '(1 2 3 4)) + ⇒ '(((1 2) 3) 4) + (--reduce (format "%s-%d" acc it) '(1 2 3)) + ⇒ "1-2-3" + + -- Function: -reduce-r (fn list) + Replace conses with FN and evaluate the resulting expression. The + final nil is ignored. If LIST contains no items, return the result + of calling FN with no arguments. If LIST contains a single item, + return that item and do not call FN. + + The first argument of FN is the new item, the second is the + accumulated value. + + Note: this function works the same as ‘-reduce’ (*note -reduce::) + but the operation associates from right instead of from left. + + See also: ‘-reduce-r-from’ (*note -reduce-r-from::), ‘-reduce’ + (*note -reduce::) + + (-reduce-r '- '(1 2 3 4)) + ⇒ -2 + (-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3)) + ⇒ "3-2-1" + (--reduce-r (format "%s-%d" acc it) '(1 2 3)) + ⇒ "3-2-1" + + -- Function: -reductions-from (fn init list) + Return a list of the intermediate values of the reduction. + + See ‘-reduce-from’ (*note -reduce-from::) for explanation of the + arguments. + + See also: ‘-reductions’ (*note -reductions::), ‘-reductions-r’ + (*note -reductions-r::), ‘-reduce-r’ (*note -reduce-r::) + + (-reductions-from (lambda (a i) (format "(%s FN %d)" a i)) "INIT" '(1 2 3 4)) + ⇒ '("INIT" "(INIT FN 1)" "((INIT FN 1) FN 2)" "(((INIT FN 1) FN 2) FN 3)" "((((INIT FN 1) FN 2) FN 3) FN 4)") + (-reductions-from 'max 0 '(2 1 4 3)) + ⇒ '(0 2 2 4 4) + (-reductions-from '* 1 '(1 2 3 4)) + ⇒ '(1 1 2 6 24) + + -- Function: -reductions-r-from (fn init list) + Return a list of the intermediate values of the reduction. + + See ‘-reduce-r-from’ (*note -reduce-r-from::) for explanation of + the arguments. + + See also: ‘-reductions-r’ (*note -reductions-r::), ‘-reductions’ + (*note -reductions::), ‘-reduce’ (*note -reduce::) + + (-reductions-r-from (lambda (i a) (format "(%d FN %s)" i a)) "INIT" '(1 2 3 4)) + ⇒ '("(1 FN (2 FN (3 FN (4 FN INIT))))" "(2 FN (3 FN (4 FN INIT)))" "(3 FN (4 FN INIT))" "(4 FN INIT)" "INIT") + (-reductions-r-from 'max 0 '(2 1 4 3)) + ⇒ '(4 4 4 3 0) + (-reductions-r-from '* 1 '(1 2 3 4)) + ⇒ '(24 24 12 4 1) + + -- Function: -reductions (fn list) + Return a list of the intermediate values of the reduction. + + See ‘-reduce’ (*note -reduce::) for explanation of the arguments. + + See also: ‘-reductions-from’ (*note -reductions-from::), + ‘-reductions-r’ (*note -reductions-r::), ‘-reduce-r’ (*note + -reduce-r::) + + (-reductions (lambda (a i) (format "(%s FN %d)" a i)) '(1 2 3 4)) + ⇒ '(1 "(1 FN 2)" "((1 FN 2) FN 3)" "(((1 FN 2) FN 3) FN 4)") + (-reductions '+ '(1 2 3 4)) + ⇒ '(1 3 6 10) + (-reductions '* '(1 2 3 4)) + ⇒ '(1 2 6 24) + + -- Function: -reductions-r (fn list) + Return a list of the intermediate values of the reduction. + + See ‘-reduce-r’ (*note -reduce-r::) for explanation of the + arguments. + + See also: ‘-reductions-r-from’ (*note -reductions-r-from::), + ‘-reductions’ (*note -reductions::), ‘-reduce’ (*note -reduce::) + + (-reductions-r (lambda (i a) (format "(%d FN %s)" i a)) '(1 2 3 4)) + ⇒ '("(1 FN (2 FN (3 FN 4)))" "(2 FN (3 FN 4))" "(3 FN 4)" 4) + (-reductions-r '+ '(1 2 3 4)) + ⇒ '(10 9 7 4) + (-reductions-r '* '(1 2 3 4)) + ⇒ '(24 24 12 4) + + -- Function: -count (pred list) + Counts the number of items in LIST where (PRED item) is non-nil. + + (-count 'even? '(1 2 3 4 5)) + ⇒ 2 + (--count (< it 4) '(1 2 3 4)) + ⇒ 3 + + -- Function: -sum (list) + Return the sum of LIST. + + (-sum '()) + ⇒ 0 + (-sum '(1)) + ⇒ 1 + (-sum '(1 2 3 4)) + ⇒ 10 + + -- Function: -running-sum (list) + Return a list with running sums of items in LIST. + + LIST must be non-empty. + + (-running-sum '(1 2 3 4)) + ⇒ '(1 3 6 10) + (-running-sum '(1)) + ⇒ '(1) + (-running-sum '()) + ⇒ error + + -- Function: -product (list) + Return the product of LIST. + + (-product '()) + ⇒ 1 + (-product '(1)) + ⇒ 1 + (-product '(1 2 3 4)) + ⇒ 24 + + -- Function: -running-product (list) + Return a list with running products of items in LIST. + + LIST must be non-empty. + + (-running-product '(1 2 3 4)) + ⇒ '(1 2 6 24) + (-running-product '(1)) + ⇒ '(1) + (-running-product '()) + ⇒ error + + -- Function: -inits (list) + Return all prefixes of LIST. + + (-inits '(1 2 3 4)) + ⇒ '(nil (1) (1 2) (1 2 3) (1 2 3 4)) + (-inits nil) + ⇒ '(nil) + (-inits '(1)) + ⇒ '(nil (1)) + + -- Function: -tails (list) + Return all suffixes of LIST + + (-tails '(1 2 3 4)) + ⇒ '((1 2 3 4) (2 3 4) (3 4) (4) nil) + (-tails nil) + ⇒ '(nil) + (-tails '(1)) + ⇒ '((1) nil) + + -- Function: -common-prefix (&rest lists) + Return the longest common prefix of LISTS. + + (-common-prefix '(1)) + ⇒ '(1) + (-common-prefix '(1 2) '(3 4) '(1 2)) + ⇒ nil + (-common-prefix '(1 2) '(1 2 3) '(1 2 3 4)) + ⇒ '(1 2) + + -- Function: -common-suffix (&rest lists) + Return the longest common suffix of LISTS. + + (-common-suffix '(1)) + ⇒ '(1) + (-common-suffix '(1 2) '(3 4) '(1 2)) + ⇒ nil + (-common-suffix '(1 2 3 4) '(2 3 4) '(3 4)) + ⇒ '(3 4) + + -- Function: -min (list) + Return the smallest value from LIST of numbers or markers. + + (-min '(0)) + ⇒ 0 + (-min '(3 2 1)) + ⇒ 1 + (-min '(1 2 3)) + ⇒ 1 + + -- Function: -min-by (comparator list) + Take a comparison function COMPARATOR and a LIST and return the + least element of the list by the comparison function. + + See also combinator ‘-on’ (*note -on::) which can transform the + values before comparing them. + + (-min-by '> '(4 3 6 1)) + ⇒ 1 + (--min-by (> (car it) (car other)) '((1 2 3) (2) (3 2))) + ⇒ '(1 2 3) + (--min-by (> (length it) (length other)) '((1 2 3) (2) (3 2))) + ⇒ '(2) + + -- Function: -max (list) + Return the largest value from LIST of numbers or markers. + + (-max '(0)) + ⇒ 0 + (-max '(3 2 1)) + ⇒ 3 + (-max '(1 2 3)) + ⇒ 3 + + -- Function: -max-by (comparator list) + Take a comparison function COMPARATOR and a LIST and return the + greatest element of the list by the comparison function. + + See also combinator ‘-on’ (*note -on::) which can transform the + values before comparing them. + + (-max-by '> '(4 3 6 1)) + ⇒ 6 + (--max-by (> (car it) (car other)) '((1 2 3) (2) (3 2))) + ⇒ '(3 2) + (--max-by (> (length it) (length other)) '((1 2 3) (2) (3 2))) + ⇒ '(1 2 3) + + +File: dash.info, Node: Unfolding, Next: Predicates, Prev: Reductions, Up: Functions + +2.5 Unfolding +============= + +Operations dual to reductions, building lists from seed value rather +than consuming a list to produce a single value. + + -- Function: -iterate (fun init n) + Return a list of iterated applications of FUN to INIT. + + This means a list of form: + + (init (fun init) (fun (fun init)) ...) + + N is the length of the returned list. + + (-iterate '1+ 1 10) + ⇒ '(1 2 3 4 5 6 7 8 9 10) + (-iterate (lambda (x) (+ x x)) 2 5) + ⇒ '(2 4 8 16 32) + (--iterate (* it it) 2 5) + ⇒ '(2 4 16 256 65536) + + -- Function: -unfold (fun seed) + Build a list from SEED using FUN. + + This is "dual" operation to ‘-reduce-r’ (*note -reduce-r::): while + -reduce-r consumes a list to produce a single value, ‘-unfold’ + (*note -unfold::) takes a seed value and builds a (potentially + infinite!) list. + + FUN should return ‘nil’ to stop the generating process, or a cons + (A . B), where A will be prepended to the result and B is the new + seed. + + (-unfold (lambda (x) (unless (= x 0) (cons x (1- x)))) 10) + ⇒ '(10 9 8 7 6 5 4 3 2 1) + (--unfold (when it (cons it (cdr it))) '(1 2 3 4)) + ⇒ '((1 2 3 4) (2 3 4) (3 4) (4)) + (--unfold (when it (cons it (butlast it))) '(1 2 3 4)) + ⇒ '((1 2 3 4) (1 2 3) (1 2) (1)) + + +File: dash.info, Node: Predicates, Next: Partitioning, Prev: Unfolding, Up: Functions + +2.6 Predicates +============== + + -- Function: -any? (pred list) + Return t if (PRED x) is non-nil for any x in LIST, else nil. + + Alias: ‘-any-p’, ‘-some?’, ‘-some-p’ + + (-any? 'even? '(1 2 3)) + ⇒ t + (-any? 'even? '(1 3 5)) + ⇒ nil + (-any? 'null '(1 3 5)) + ⇒ nil + + -- Function: -all? (pred list) + Return t if (PRED x) is non-nil for all x in LIST, else nil. + + Alias: ‘-all-p’, ‘-every?’, ‘-every-p’ + + (-all? 'even? '(1 2 3)) + ⇒ nil + (-all? 'even? '(2 4 6)) + ⇒ t + (--all? (= 0 (% it 2)) '(2 4 6)) + ⇒ t + + -- Function: -none? (pred list) + Return t if (PRED x) is nil for all x in LIST, else nil. + + Alias: ‘-none-p’ + + (-none? 'even? '(1 2 3)) + ⇒ nil + (-none? 'even? '(1 3 5)) + ⇒ t + (--none? (= 0 (% it 2)) '(1 2 3)) + ⇒ nil + + -- Function: -only-some? (pred list) + Return ‘t‘ if at least one item of LIST matches PRED and at least + one item of LIST does not match PRED. Return ‘nil‘ both if all + items match the predicate or if none of the items match the + predicate. + + Alias: ‘-only-some-p’ + + (-only-some? 'even? '(1 2 3)) + ⇒ t + (-only-some? 'even? '(1 3 5)) + ⇒ nil + (-only-some? 'even? '(2 4 6)) + ⇒ nil + + -- Function: -contains? (list element) + Return non-nil if LIST contains ELEMENT. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that’s non-nil. + + Alias: ‘-contains-p’ + + (-contains? '(1 2 3) 1) + ⇒ t + (-contains? '(1 2 3) 2) + ⇒ t + (-contains? '(1 2 3) 4) + ⇒ nil + + -- Function: -same-items? (list list2) + Return true if LIST and LIST2 has the same items. + + The order of the elements in the lists does not matter. + + Alias: ‘-same-items-p’ + + (-same-items? '(1 2 3) '(1 2 3)) + ⇒ t + (-same-items? '(1 2 3) '(3 2 1)) + ⇒ t + (-same-items? '(1 2 3) '(1 2 3 4)) + ⇒ nil + + -- Function: -is-prefix? (prefix list) + Return non-nil if PREFIX is prefix of LIST. + + Alias: ‘-is-prefix-p’ + + (-is-prefix? '(1 2 3) '(1 2 3 4 5)) + ⇒ t + (-is-prefix? '(1 2 3 4 5) '(1 2 3)) + ⇒ nil + (-is-prefix? '(1 3) '(1 2 3 4 5)) + ⇒ nil + + -- Function: -is-suffix? (suffix list) + Return non-nil if SUFFIX is suffix of LIST. + + Alias: ‘-is-suffix-p’ + + (-is-suffix? '(3 4 5) '(1 2 3 4 5)) + ⇒ t + (-is-suffix? '(1 2 3 4 5) '(3 4 5)) + ⇒ nil + (-is-suffix? '(3 5) '(1 2 3 4 5)) + ⇒ nil + + -- Function: -is-infix? (infix list) + Return non-nil if INFIX is infix of LIST. + + This operation runs in O(n^2) time + + Alias: ‘-is-infix-p’ + + (-is-infix? '(1 2 3) '(1 2 3 4 5)) + ⇒ t + (-is-infix? '(2 3 4) '(1 2 3 4 5)) + ⇒ t + (-is-infix? '(3 4 5) '(1 2 3 4 5)) + ⇒ t + + +File: dash.info, Node: Partitioning, Next: Indexing, Prev: Predicates, Up: Functions + +2.7 Partitioning +================ + +Functions partitioning the input list into a list of lists. + + -- Function: -split-at (n list) + Return a list of ((-take N LIST) (-drop N LIST)), in no more than + one pass through the list. + + (-split-at 3 '(1 2 3 4 5)) + ⇒ '((1 2 3) (4 5)) + (-split-at 17 '(1 2 3 4 5)) + ⇒ '((1 2 3 4 5) nil) + + -- Function: -split-with (pred list) + Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), + in no more than one pass through the list. + + (-split-with 'even? '(1 2 3 4)) + ⇒ '(nil (1 2 3 4)) + (-split-with 'even? '(2 4 5 6)) + ⇒ '((2 4) (5 6)) + (--split-with (< it 4) '(1 2 3 4 3 2 1)) + ⇒ '((1 2 3) (4 3 2 1)) + + -- Macro: -split-on (item list) + Split the LIST each time ITEM is found. + + Unlike ‘-partition-by’ (*note -partition-by::), the ITEM is + discarded from the results. Empty lists are also removed from the + result. + + Comparison is done by ‘equal’. + + See also ‘-split-when’ (*note -split-when::) + + (-split-on '| '(Nil | Leaf a | Node [Tree a])) + ⇒ '((Nil) (Leaf a) (Node [Tree a])) + (-split-on ':endgroup '("a" "b" :endgroup "c" :endgroup "d" "e")) + ⇒ '(("a" "b") ("c") ("d" "e")) + (-split-on ':endgroup '("a" "b" :endgroup :endgroup "d" "e")) + ⇒ '(("a" "b") ("d" "e")) + + -- Function: -split-when (fn list) + Split the LIST on each element where FN returns non-nil. + + Unlike ‘-partition-by’ (*note -partition-by::), the "matched" + element is discarded from the results. Empty lists are also + removed from the result. + + This function can be thought of as a generalization of + ‘split-string’. + + (-split-when 'even? '(1 2 3 4 5 6)) + ⇒ '((1) (3) (5)) + (-split-when 'even? '(1 2 3 4 6 8 9)) + ⇒ '((1) (3) (9)) + (--split-when (memq it '(&optional &rest)) '(a b &optional c d &rest args)) + ⇒ '((a b) (c d) (args)) + + -- Function: -separate (pred list) + Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one + pass through the list. + + (-separate (lambda (num) (= 0 (% num 2))) '(1 2 3 4 5 6 7)) + ⇒ '((2 4 6) (1 3 5 7)) + (--separate (< it 5) '(3 7 5 9 3 2 1 4 6)) + ⇒ '((3 3 2 1 4) (7 5 9 6)) + (-separate 'cdr '((1 2) (1) (1 2 3) (4))) + ⇒ '(((1 2) (1 2 3)) ((1) (4))) + + -- Function: -partition (n list) + Return a new list with the items in LIST grouped into N-sized + sublists. If there are not enough items to make the last group + N-sized, those items are discarded. + + (-partition 2 '(1 2 3 4 5 6)) + ⇒ '((1 2) (3 4) (5 6)) + (-partition 2 '(1 2 3 4 5 6 7)) + ⇒ '((1 2) (3 4) (5 6)) + (-partition 3 '(1 2 3 4 5 6 7)) + ⇒ '((1 2 3) (4 5 6)) + + -- Function: -partition-all (n list) + Return a new list with the items in LIST grouped into N-sized + sublists. The last group may contain less than N items. + + (-partition-all 2 '(1 2 3 4 5 6)) + ⇒ '((1 2) (3 4) (5 6)) + (-partition-all 2 '(1 2 3 4 5 6 7)) + ⇒ '((1 2) (3 4) (5 6) (7)) + (-partition-all 3 '(1 2 3 4 5 6 7)) + ⇒ '((1 2 3) (4 5 6) (7)) + + -- Function: -partition-in-steps (n step list) + Return a new list with the items in LIST grouped into N-sized + sublists at offsets STEP apart. If there are not enough items to + make the last group N-sized, those items are discarded. + + (-partition-in-steps 2 1 '(1 2 3 4)) + ⇒ '((1 2) (2 3) (3 4)) + (-partition-in-steps 3 2 '(1 2 3 4)) + ⇒ '((1 2 3)) + (-partition-in-steps 3 2 '(1 2 3 4 5)) + ⇒ '((1 2 3) (3 4 5)) + + -- Function: -partition-all-in-steps (n step list) + Return a new list with the items in LIST grouped into N-sized + sublists at offsets STEP apart. The last groups may contain less + than N items. + + (-partition-all-in-steps 2 1 '(1 2 3 4)) + ⇒ '((1 2) (2 3) (3 4) (4)) + (-partition-all-in-steps 3 2 '(1 2 3 4)) + ⇒ '((1 2 3) (3 4)) + (-partition-all-in-steps 3 2 '(1 2 3 4 5)) + ⇒ '((1 2 3) (3 4 5) (5)) + + -- Function: -partition-by (fn list) + Apply FN to each item in LIST, splitting it each time FN returns a + new value. + + (-partition-by 'even? '()) + ⇒ '() + (-partition-by 'even? '(1 1 2 2 2 3 4 6 8)) + ⇒ '((1 1) (2 2 2) (3) (4 6 8)) + (--partition-by (< it 3) '(1 2 3 4 3 2 1)) + ⇒ '((1 2) (3 4 3) (2 1)) + + -- Function: -partition-by-header (fn list) + Apply FN to the first item in LIST. That is the header value. + Apply FN to each item in LIST, splitting it each time FN returns + the header value, but only after seeing at least one other value + (the body). + + (--partition-by-header (= it 1) '(1 2 3 1 2 1 2 3 4)) + ⇒ '((1 2 3) (1 2) (1 2 3 4)) + (--partition-by-header (> it 0) '(1 2 0 1 0 1 2 3 0)) + ⇒ '((1 2 0) (1 0) (1 2 3 0)) + (-partition-by-header 'even? '(2 1 1 1 4 1 3 5 6 6 1)) + ⇒ '((2 1 1 1) (4 1 3 5) (6 6 1)) + + -- Function: -partition-after-pred (pred list) + Partition directly after each time PRED is true on an element of + LIST. + + (-partition-after-pred #'odd? '()) + ⇒ '() + (-partition-after-pred #'odd? '(1)) + ⇒ '((1)) + (-partition-after-pred #'odd? '(0 1)) + ⇒ '((0 1)) + + -- Function: -partition-before-pred (pred list) + Partition directly before each time PRED is true on an element of + LIST. + + (-partition-before-pred #'odd? '()) + ⇒ '() + (-partition-before-pred #'odd? '(1)) + ⇒ '((1)) + (-partition-before-pred #'odd? '(0 1)) + ⇒ '((0) (1)) + + -- Function: -partition-before-item (item list) + Partition directly before each time ITEM appears in LIST. + + (-partition-before-item 3 '()) + ⇒ '() + (-partition-before-item 3 '(1)) + ⇒ '((1)) + (-partition-before-item 3 '(3)) + ⇒ '((3)) + + -- Function: -partition-after-item (item list) + Partition directly after each time ITEM appears in LIST. + + (-partition-after-item 3 '()) + ⇒ '() + (-partition-after-item 3 '(1)) + ⇒ '((1)) + (-partition-after-item 3 '(3)) + ⇒ '((3)) + + -- Function: -group-by (fn list) + Separate LIST into an alist whose keys are FN applied to the + elements of LIST. Keys are compared by ‘equal’. + + (-group-by 'even? '()) + ⇒ '() + (-group-by 'even? '(1 1 2 2 2 3 4 6 8)) + ⇒ '((nil 1 1 3) (t 2 2 2 4 6 8)) + (--group-by (car (split-string it "/")) '("a/b" "c/d" "a/e")) + ⇒ '(("a" "a/b" "a/e") ("c" "c/d")) + + +File: dash.info, Node: Indexing, Next: Set operations, Prev: Partitioning, Up: Functions + +2.8 Indexing +============ + +Return indices of elements based on predicates, sort elements by indices +etc. + + -- Function: -elem-index (elem list) + Return the index of the first element in the given LIST which is + equal to the query element ELEM, or nil if there is no such + element. + + (-elem-index 2 '(6 7 8 2 3 4)) + ⇒ 3 + (-elem-index "bar" '("foo" "bar" "baz")) + ⇒ 1 + (-elem-index '(1 2) '((3) (5 6) (1 2) nil)) + ⇒ 2 + + -- Function: -elem-indices (elem list) + Return the indices of all elements in LIST equal to the query + element ELEM, in ascending order. + + (-elem-indices 2 '(6 7 8 2 3 4 2 1)) + ⇒ '(3 6) + (-elem-indices "bar" '("foo" "bar" "baz")) + ⇒ '(1) + (-elem-indices '(1 2) '((3) (1 2) (5 6) (1 2) nil)) + ⇒ '(1 3) + + -- Function: -find-index (pred list) + Take a predicate PRED and a LIST and return the index of the first + element in the list satisfying the predicate, or nil if there is no + such element. + + See also ‘-first’ (*note -first::). + + (-find-index 'even? '(2 4 1 6 3 3 5 8)) + ⇒ 0 + (--find-index (< 5 it) '(2 4 1 6 3 3 5 8)) + ⇒ 3 + (-find-index (-partial 'string-lessp "baz") '("bar" "foo" "baz")) + ⇒ 1 + + -- Function: -find-last-index (pred list) + Take a predicate PRED and a LIST and return the index of the last + element in the list satisfying the predicate, or nil if there is no + such element. + + See also ‘-last’ (*note -last::). + + (-find-last-index 'even? '(2 4 1 6 3 3 5 8)) + ⇒ 7 + (--find-last-index (< 5 it) '(2 7 1 6 3 8 5 2)) + ⇒ 5 + (-find-last-index (-partial 'string-lessp "baz") '("q" "foo" "baz")) + ⇒ 1 + + -- Function: -find-indices (pred list) + Return the indices of all elements in LIST satisfying the predicate + PRED, in ascending order. + + (-find-indices 'even? '(2 4 1 6 3 3 5 8)) + ⇒ '(0 1 3 7) + (--find-indices (< 5 it) '(2 4 1 6 3 3 5 8)) + ⇒ '(3 7) + (-find-indices (-partial 'string-lessp "baz") '("bar" "foo" "baz")) + ⇒ '(1) + + -- Function: -grade-up (comparator list) + Grade elements of LIST using COMPARATOR relation, yielding a + permutation vector such that applying this permutation to LIST + sorts it in ascending order. + + (-grade-up '< '(3 1 4 2 1 3 3)) + ⇒ '(1 4 3 0 5 6 2) + (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-up '< l) l)) + ⇒ '(1 1 2 3 3 3 4) + + -- Function: -grade-down (comparator list) + Grade elements of LIST using COMPARATOR relation, yielding a + permutation vector such that applying this permutation to LIST + sorts it in descending order. + + (-grade-down '< '(3 1 4 2 1 3 3)) + ⇒ '(2 0 5 6 3 1 4) + (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-down '< l) l)) + ⇒ '(4 3 3 3 2 1 1) + + +File: dash.info, Node: Set operations, Next: Other list operations, Prev: Indexing, Up: Functions + +2.9 Set operations +================== + +Operations pretending lists are sets. + + -- Function: -union (list list2) + Return a new list containing the elements of LIST and elements of + LIST2 that are not in LIST. The test for equality is done with + ‘equal’, or with ‘-compare-fn’ if that’s non-nil. + + (-union '(1 2 3) '(3 4 5)) + ⇒ '(1 2 3 4 5) + (-union '(1 2 3 4) '()) + ⇒ '(1 2 3 4) + (-union '(1 1 2 2) '(3 2 1)) + ⇒ '(1 1 2 2 3) + + -- Function: -difference (list list2) + Return a new list with only the members of LIST that are not in + LIST2. The test for equality is done with ‘equal’, or with + ‘-compare-fn’ if that’s non-nil. + + (-difference '() '()) + ⇒ '() + (-difference '(1 2 3) '(4 5 6)) + ⇒ '(1 2 3) + (-difference '(1 2 3 4) '(3 4 5 6)) + ⇒ '(1 2) + + -- Function: -intersection (list list2) + Return a new list containing only the elements that are members of + both LIST and LIST2. The test for equality is done with ‘equal’, + or with ‘-compare-fn’ if that’s non-nil. + + (-intersection '() '()) + ⇒ '() + (-intersection '(1 2 3) '(4 5 6)) + ⇒ '() + (-intersection '(1 2 3 4) '(3 4 5 6)) + ⇒ '(3 4) + + -- Function: -powerset (list) + Return the power set of LIST. + + (-powerset '()) + ⇒ '(nil) + (-powerset '(x y z)) + ⇒ '((x y z) (x y) (x z) (x) (y z) (y) (z) nil) + + -- Function: -permutations (list) + Return the permutations of LIST. + + (-permutations '()) + ⇒ '(nil) + (-permutations '(1 2)) + ⇒ '((1 2) (2 1)) + (-permutations '(a b c)) + ⇒ '((a b c) (a c b) (b a c) (b c a) (c a b) (c b a)) + + -- Function: -distinct (list) + Return a new list with all duplicates removed. The test for + equality is done with ‘equal’, or with ‘-compare-fn’ if that’s + non-nil. + + Alias: ‘-uniq’ + + (-distinct '()) + ⇒ '() + (-distinct '(1 2 2 4)) + ⇒ '(1 2 4) + (-distinct '(t t t)) + ⇒ '(t) + + +File: dash.info, Node: Other list operations, Next: Tree operations, Prev: Set operations, Up: Functions + +2.10 Other list operations +========================== + +Other list functions not fit to be classified elsewhere. + + -- Function: -rotate (n list) + Rotate LIST N places to the right. With N negative, rotate to the + left. The time complexity is O(n). + + (-rotate 3 '(1 2 3 4 5 6 7)) + ⇒ '(5 6 7 1 2 3 4) + (-rotate -3 '(1 2 3 4 5 6 7)) + ⇒ '(4 5 6 7 1 2 3) + (-rotate 16 '(1 2 3 4 5 6 7)) + ⇒ '(6 7 1 2 3 4 5) + + -- Function: -repeat (n x) + Return a list with X repeated N times. Return nil if N is less + than 1. + + (-repeat 3 :a) + ⇒ '(:a :a :a) + (-repeat 1 :a) + ⇒ '(:a) + (-repeat 0 :a) + ⇒ nil + + -- Function: -cons* (&rest args) + Make a new list from the elements of ARGS. + + The last 2 members of ARGS are used as the final cons of the result + so if the final member of ARGS is not a list the result is a dotted + list. + + (-cons* 1 2) + ⇒ '(1 . 2) + (-cons* 1 2 3) + ⇒ '(1 2 . 3) + (-cons* 1) + ⇒ 1 + + -- Function: -snoc (list elem &rest elements) + Append ELEM to the end of the list. + + This is like ‘cons’, but operates on the end of list. + + If ELEMENTS is non nil, append these to the list as well. + + (-snoc '(1 2 3) 4) + ⇒ '(1 2 3 4) + (-snoc '(1 2 3) 4 5 6) + ⇒ '(1 2 3 4 5 6) + (-snoc '(1 2 3) '(4 5 6)) + ⇒ '(1 2 3 (4 5 6)) + + -- Function: -interpose (sep list) + Return a new list of all elements in LIST separated by SEP. + + (-interpose "-" '()) + ⇒ '() + (-interpose "-" '("a")) + ⇒ '("a") + (-interpose "-" '("a" "b" "c")) + ⇒ '("a" "-" "b" "-" "c") + + -- Function: -interleave (&rest lists) + Return a new list of the first item in each list, then the second + etc. + + (-interleave '(1 2) '("a" "b")) + ⇒ '(1 "a" 2 "b") + (-interleave '(1 2) '("a" "b") '("A" "B")) + ⇒ '(1 "a" "A" 2 "b" "B") + (-interleave '(1 2 3) '("a" "b")) + ⇒ '(1 "a" 2 "b") + + -- Function: -zip-with (fn list1 list2) + Zip the two lists LIST1 and LIST2 using a function FN. This + function is applied pairwise taking as first argument element of + LIST1 and as second argument element of LIST2 at corresponding + position. + + The anaphoric form ‘--zip-with’ binds the elements from LIST1 as + symbol ‘it’, and the elements from LIST2 as symbol ‘other’. + + (-zip-with '+ '(1 2 3) '(4 5 6)) + ⇒ '(5 7 9) + (-zip-with 'cons '(1 2 3) '(4 5 6)) + ⇒ '((1 . 4) (2 . 5) (3 . 6)) + (--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde")) + ⇒ '("Batman and Robin" "Jekyll and Hyde") + + -- Function: -zip (&rest lists) + Zip LISTS together. Group the head of each list, followed by the + second elements of each list, and so on. The lengths of the + returned groupings are equal to the length of the shortest input + list. + + If two lists are provided as arguments, return the groupings as a + list of cons cells. Otherwise, return the groupings as a list of + lists. + + Use ‘-zip-lists’ (*note -zip-lists::) if you need the return value + to always be a list of lists. + + Alias: ‘-zip-pair’ + + See also: ‘-zip-lists’ (*note -zip-lists::) + + (-zip '(1 2 3) '(4 5 6)) + ⇒ '((1 . 4) (2 . 5) (3 . 6)) + (-zip '(1 2 3) '(4 5 6 7)) + ⇒ '((1 . 4) (2 . 5) (3 . 6)) + (-zip '(1 2) '(3 4 5) '(6)) + ⇒ '((1 3 6)) + + -- Function: -zip-lists (&rest lists) + Zip LISTS together. Group the head of each list, followed by the + second elements of each list, and so on. The lengths of the + returned groupings are equal to the length of the shortest input + list. + + The return value is always list of lists, which is a difference + from ‘-zip-pair’ which returns a cons-cell in case two input lists + are provided. + + See also: ‘-zip’ (*note -zip::) + + (-zip-lists '(1 2 3) '(4 5 6)) + ⇒ '((1 4) (2 5) (3 6)) + (-zip-lists '(1 2 3) '(4 5 6 7)) + ⇒ '((1 4) (2 5) (3 6)) + (-zip-lists '(1 2) '(3 4 5) '(6)) + ⇒ '((1 3 6)) + + -- Function: -zip-fill (fill-value &rest lists) + Zip LISTS, with FILL-VALUE padded onto the shorter lists. The + lengths of the returned groupings are equal to the length of the + longest input list. + + (-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) + ⇒ '((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0)) + + -- Function: -unzip (lists) + Unzip LISTS. + + This works just like ‘-zip’ (*note -zip::) but takes a list of + lists instead of a variable number of arguments, such that + + (-unzip (-zip L1 L2 L3 ...)) + + is identity (given that the lists are the same length). + + Note in particular that calling this on a list of two lists will + return a list of cons-cells such that the above identity works. + + See also: ‘-zip’ (*note -zip::) + + (-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g"))) + ⇒ '((1 2 3) (a b c) ("e" "f" "g")) + (-unzip '((1 2) (3 4) (5 6) (7 8) (9 10))) + ⇒ '((1 3 5 7 9) (2 4 6 8 10)) + (-unzip '((1 2) (3 4))) + ⇒ '((1 . 3) (2 . 4)) + + -- Function: -cycle (list) + Return an infinite copy of LIST that will cycle through the + elements and repeat from the beginning. + + (-take 5 (-cycle '(1 2 3))) + ⇒ '(1 2 3 1 2) + (-take 7 (-cycle '(1 "and" 3))) + ⇒ '(1 "and" 3 1 "and" 3 1) + (-zip (-cycle '(1 2 3)) '(1 2)) + ⇒ '((1 . 1) (2 . 2)) + + -- Function: -pad (fill-value &rest lists) + Appends FILL-VALUE to the end of each list in LISTS such that they + will all have the same length. + + (-pad 0 '()) + ⇒ '(nil) + (-pad 0 '(1)) + ⇒ '((1)) + (-pad 0 '(1 2 3) '(4 5)) + ⇒ '((1 2 3) (4 5 0)) + + -- Function: -table (fn &rest lists) + Compute outer product of LISTS using function FN. + + The function FN should have the same arity as the number of + supplied lists. + + The outer product is computed by applying fn to all possible + combinations created by taking one element from each list in order. + The dimension of the result is (length lists). + + See also: ‘-table-flat’ (*note -table-flat::) + + (-table '* '(1 2 3) '(1 2 3)) + ⇒ '((1 2 3) (2 4 6) (3 6 9)) + (-table (lambda (a b) (-sum (-zip-with '* a b))) '((1 2) (3 4)) '((1 3) (2 4))) + ⇒ '((7 15) (10 22)) + (apply '-table 'list (-repeat 3 '(1 2))) + ⇒ '((((1 1 1) (2 1 1)) ((1 2 1) (2 2 1))) (((1 1 2) (2 1 2)) ((1 2 2) (2 2 2)))) + + -- Function: -table-flat (fn &rest lists) + Compute flat outer product of LISTS using function FN. + + The function FN should have the same arity as the number of + supplied lists. + + The outer product is computed by applying fn to all possible + combinations created by taking one element from each list in order. + The results are flattened, ignoring the tensor structure of the + result. This is equivalent to calling: + + (-flatten-n (1- (length lists)) (apply ’-table fn lists)) + + but the implementation here is much more efficient. + + See also: ‘-flatten-n’ (*note -flatten-n::), ‘-table’ (*note + -table::) + + (-table-flat 'list '(1 2 3) '(a b c)) + ⇒ '((1 a) (2 a) (3 a) (1 b) (2 b) (3 b) (1 c) (2 c) (3 c)) + (-table-flat '* '(1 2 3) '(1 2 3)) + ⇒ '(1 2 3 2 4 6 3 6 9) + (apply '-table-flat 'list (-repeat 3 '(1 2))) + ⇒ '((1 1 1) (2 1 1) (1 2 1) (2 2 1) (1 1 2) (2 1 2) (1 2 2) (2 2 2)) + + -- Function: -first (pred list) + Return the first x in LIST where (PRED x) is non-nil, else nil. + + To get the first item in the list no questions asked, use ‘car’. + + Alias: ‘-find’ + + (-first 'even? '(1 2 3)) + ⇒ 2 + (-first 'even? '(1 3 5)) + ⇒ nil + (-first 'null '(1 3 5)) + ⇒ nil + + -- Function: -some (pred list) + Return (PRED x) for the first LIST item where (PRED x) is non-nil, + else nil. + + Alias: ‘-any’ + + (-some 'even? '(1 2 3)) + ⇒ t + (-some 'null '(1 2 3)) + ⇒ nil + (-some 'null '(1 2 nil)) + ⇒ t + + -- Function: -last (pred list) + Return the last x in LIST where (PRED x) is non-nil, else nil. + + (-last 'even? '(1 2 3 4 5 6 3 3 3)) + ⇒ 6 + (-last 'even? '(1 3 7 5 9)) + ⇒ nil + (--last (> (length it) 3) '("a" "looong" "word" "and" "short" "one")) + ⇒ "short" + + -- Function: -first-item (list) + Return the first item of LIST, or nil on an empty list. + + See also: ‘-second-item’ (*note -second-item::), ‘-last-item’ + (*note -last-item::). + + (fn LIST) + + (-first-item '(1 2 3)) + ⇒ 1 + (-first-item nil) + ⇒ nil + (let ((list (list 1 2 3))) (setf (-first-item list) 5) list) + ⇒ '(5 2 3) + + -- Function: -second-item (arg1) + Return the second item of LIST, or nil if LIST is too short. + + See also: ‘-third-item’ (*note -third-item::). + + (fn LIST) + + (-second-item '(1 2 3)) + ⇒ 2 + (-second-item nil) + ⇒ nil + + -- Function: -third-item (arg1) + Return the third item of LIST, or nil if LIST is too short. + + See also: ‘-fourth-item’ (*note -fourth-item::). + + (fn LIST) + + (-third-item '(1 2 3)) + ⇒ 3 + (-third-item nil) + ⇒ nil + + -- Function: -fourth-item (list) + Return the fourth item of LIST, or nil if LIST is too short. + + See also: ‘-fifth-item’ (*note -fifth-item::). + + (-fourth-item '(1 2 3 4)) + ⇒ 4 + (-fourth-item nil) + ⇒ nil + + -- Function: -fifth-item (list) + Return the fifth item of LIST, or nil if LIST is too short. + + See also: ‘-last-item’ (*note -last-item::). + + (-fifth-item '(1 2 3 4 5)) + ⇒ 5 + (-fifth-item nil) + ⇒ nil + + -- Function: -last-item (list) + Return the last item of LIST, or nil on an empty list. + + (-last-item '(1 2 3)) + ⇒ 3 + (-last-item nil) + ⇒ nil + (let ((list (list 1 2 3))) (setf (-last-item list) 5) list) + ⇒ '(1 2 5) + + -- Function: -butlast (list) + Return a list of all items in list except for the last. + + (-butlast '(1 2 3)) + ⇒ '(1 2) + (-butlast '(1 2)) + ⇒ '(1) + (-butlast '(1)) + ⇒ nil + + -- Function: -sort (comparator list) + Sort LIST, stably, comparing elements using COMPARATOR. Return the + sorted list. LIST is NOT modified by side effects. COMPARATOR is + called with two elements of LIST, and should return non-nil if the + first element should sort before the second. + + (-sort '< '(3 1 2)) + ⇒ '(1 2 3) + (-sort '> '(3 1 2)) + ⇒ '(3 2 1) + (--sort (< it other) '(3 1 2)) + ⇒ '(1 2 3) + + -- Function: -list (&rest args) + Return a list with ARGS. + + If first item of ARGS is already a list, simply return ARGS. If + not, return a list with ARGS as elements. + + (-list 1) + ⇒ '(1) + (-list 1 2 3) + ⇒ '(1 2 3) + (-list '(1 2 3)) + ⇒ '(1 2 3) + + -- Function: -fix (fn list) + Compute the (least) fixpoint of FN with initial input LIST. + + FN is called at least once, results are compared with ‘equal’. + + (-fix (lambda (l) (-non-nil (--mapcat (-split-at (/ (length it) 2) it) l))) '((1 2 3 4 5 6))) + ⇒ '((1) (2) (3) (4) (5) (6)) + (let ((data '(("starwars" "scifi") ("jedi" "starwars" "warrior")))) (--fix (-uniq (--mapcat (cons it (cdr (assoc it data))) it)) '("jedi" "book"))) + ⇒ '("jedi" "starwars" "warrior" "scifi" "book") + + +File: dash.info, Node: Tree operations, Next: Threading macros, Prev: Other list operations, Up: Functions + +2.11 Tree operations +==================== + +Functions pretending lists are trees. + + -- Function: -tree-seq (branch children tree) + Return a sequence of the nodes in TREE, in depth-first search + order. + + BRANCH is a predicate of one argument that returns non-nil if the + passed argument is a branch, that is, a node that can have + children. + + CHILDREN is a function of one argument that returns the children of + the passed branch node. + + Non-branch nodes are simply copied. + + (-tree-seq 'listp 'identity '(1 (2 3) 4 (5 (6 7)))) + ⇒ '((1 (2 3) 4 (5 (6 7))) 1 (2 3) 2 3 4 (5 (6 7)) 5 (6 7) 6 7) + (-tree-seq 'listp 'reverse '(1 (2 3) 4 (5 (6 7)))) + ⇒ '((1 (2 3) 4 (5 (6 7))) (5 (6 7)) (6 7) 7 6 5 4 (2 3) 3 2 1) + (--tree-seq (vectorp it) (append it nil) [1 [2 3] 4 [5 [6 7]]]) + ⇒ '([1 [2 3] 4 [5 [6 7]]] 1 [2 3] 2 3 4 [5 [6 7]] 5 [6 7] 6 7) + + -- Function: -tree-map (fn tree) + Apply FN to each element of TREE while preserving the tree + structure. + + (-tree-map '1+ '(1 (2 3) (4 (5 6) 7))) + ⇒ '(2 (3 4) (5 (6 7) 8)) + (-tree-map '(lambda (x) (cons x (expt 2 x))) '(1 (2 3) 4)) + ⇒ '((1 . 2) ((2 . 4) (3 . 8)) (4 . 16)) + (--tree-map (length it) '("<body>" ("<p>" "text" "</p>") "</body>")) + ⇒ '(6 (3 4 4) 7) + + -- Function: -tree-map-nodes (pred fun tree) + Call FUN on each node of TREE that satisfies PRED. + + If PRED returns nil, continue descending down this node. If PRED + returns non-nil, apply FUN to this node and do not descend further. + + (-tree-map-nodes 'vectorp (lambda (x) (-sum (append x nil))) '(1 [2 3] 4 (5 [6 7] 8))) + ⇒ '(1 5 4 (5 13 8)) + (-tree-map-nodes 'keywordp (lambda (x) (symbol-name x)) '(1 :foo 4 ((5 6 :bar) :baz 8))) + ⇒ '(1 ":foo" 4 ((5 6 ":bar") ":baz" 8)) + (--tree-map-nodes (eq (car-safe it) 'add-mode) (-concat it (list :mode 'emacs-lisp-mode)) '(with-mode emacs-lisp-mode (foo bar) (add-mode a b) (baz (add-mode c d)))) + ⇒ '(with-mode emacs-lisp-mode (foo bar) (add-mode a b :mode emacs-lisp-mode) (baz (add-mode c d :mode emacs-lisp-mode))) + + -- Function: -tree-reduce (fn tree) + Use FN to reduce elements of list TREE. If elements of TREE are + lists themselves, apply the reduction recursively. + + FN is first applied to first element of the list and second + element, then on this result and third element from the list etc. + + See ‘-reduce-r’ (*note -reduce-r::) for how exactly are lists of + zero or one element handled. + + (-tree-reduce '+ '(1 (2 3) (4 5))) + ⇒ 15 + (-tree-reduce 'concat '("strings" (" on" " various") ((" levels")))) + ⇒ "strings on various levels" + (--tree-reduce (cond ((stringp it) (concat it " " acc)) (t (let ((sn (symbol-name it))) (concat "<" sn ">" acc "</" sn ">")))) '(body (p "some words") (div "more" (b "bold") "words"))) + ⇒ "<body><p>some words</p> <div>more <b>bold</b> words</div></body>" + + -- Function: -tree-reduce-from (fn init-value tree) + Use FN to reduce elements of list TREE. If elements of TREE are + lists themselves, apply the reduction recursively. + + FN is first applied to INIT-VALUE and first element of the list, + then on this result and second element from the list etc. + + The initial value is ignored on cons pairs as they always contain + two elements. + + (-tree-reduce-from '+ 1 '(1 (1 1) ((1)))) + ⇒ 8 + (--tree-reduce-from (-concat acc (list it)) nil '(1 (2 3 (4 5)) (6 7))) + ⇒ '((7 6) ((5 4) 3 2) 1) + + -- Function: -tree-mapreduce (fn folder tree) + Apply FN to each element of TREE, and make a list of the results. + If elements of TREE are lists themselves, apply FN recursively to + elements of these nested lists. + + Then reduce the resulting lists using FOLDER and initial value + INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::). + + This is the same as calling ‘-tree-reduce’ (*note -tree-reduce::) + after ‘-tree-map’ (*note -tree-map::) but is twice as fast as it + only traverse the structure once. + + (-tree-mapreduce 'list 'append '(1 (2 (3 4) (5 6)) (7 (8 9)))) + ⇒ '(1 2 3 4 5 6 7 8 9) + (--tree-mapreduce 1 (+ it acc) '(1 (2 (4 9) (2 1)) (7 (4 3)))) + ⇒ 9 + (--tree-mapreduce 0 (max acc (1+ it)) '(1 (2 (4 9) (2 1)) (7 (4 3)))) + ⇒ 3 + + -- Function: -tree-mapreduce-from (fn folder init-value tree) + Apply FN to each element of TREE, and make a list of the results. + If elements of TREE are lists themselves, apply FN recursively to + elements of these nested lists. + + Then reduce the resulting lists using FOLDER and initial value + INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::). + + This is the same as calling ‘-tree-reduce-from’ (*note + -tree-reduce-from::) after ‘-tree-map’ (*note -tree-map::) but is + twice as fast as it only traverse the structure once. + + (-tree-mapreduce-from 'identity '* 1 '(1 (2 (3 4) (5 6)) (7 (8 9)))) + ⇒ 362880 + (--tree-mapreduce-from (+ it it) (cons it acc) nil '(1 (2 (4 9) (2 1)) (7 (4 3)))) + ⇒ '(2 (4 (8 18) (4 2)) (14 (8 6))) + (concat "{" (--tree-mapreduce-from (cond ((-cons-pair? it) (concat (symbol-name (car it)) " -> " (symbol-name (cdr it)))) (t (concat (symbol-name it) " : {"))) (concat it (unless (or (equal acc "}") (equal (substring it (1- (length it))) "{")) ", ") acc) "}" '((elips-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam))))) + ⇒ "{elips-mode : {foo : {bar -> booze{, baz -> qux{, c-mode : {foo -> bla, bum -> bam}}" + + -- Function: -clone (list) + Create a deep copy of LIST. The new list has the same elements and + structure but all cons are replaced with new ones. This is useful + when you need to clone a structure such as plist or alist. + + (let* ((a '(1 2 3)) (b (-clone a))) (nreverse a) b) + ⇒ '(1 2 3) + + +File: dash.info, Node: Threading macros, Next: Binding, Prev: Tree operations, Up: Functions + +2.12 Threading macros +===================== + + -- Macro: -> (x &optional form &rest more) + Thread the expr through the forms. Insert X as the second item in + the first form, making a list of it if it is not a list already. + If there are more forms, insert the first form as the second item + in second form, etc. + + (-> '(2 3 5)) + ⇒ '(2 3 5) + (-> '(2 3 5) (append '(8 13))) + ⇒ '(2 3 5 8 13) + (-> '(2 3 5) (append '(8 13)) (-slice 1 -1)) + ⇒ '(3 5 8) + + -- Macro: ->> (x &optional form &rest more) + Thread the expr through the forms. Insert X as the last item in + the first form, making a list of it if it is not a list already. + If there are more forms, insert the first form as the last item in + second form, etc. + + (->> '(1 2 3) (-map 'square)) + ⇒ '(1 4 9) + (->> '(1 2 3) (-map 'square) (-remove 'even?)) + ⇒ '(1 9) + (->> '(1 2 3) (-map 'square) (-reduce '+)) + ⇒ 14 + + -- Macro: --> (x &rest forms) + Starting with the value of X, thread each expression through FORMS. + + Insert X at the position signified by the symbol ‘it’ in the first + form. If there are more forms, insert the first form at the + position signified by ‘it’ in in second form, etc. + + (--> "def" (concat "abc" it "ghi")) + ⇒ "abcdefghi" + (--> "def" (concat "abc" it "ghi") (upcase it)) + ⇒ "ABCDEFGHI" + (--> "def" (concat "abc" it "ghi") upcase) + ⇒ "ABCDEFGHI" + + -- Macro: -as-> (value variable &rest forms) + Starting with VALUE, thread VARIABLE through FORMS. + + In the first form, bind VARIABLE to VALUE. In the second form, + bind VARIABLE to the result of the first form, and so forth. + + (-as-> 3 my-var (1+ my-var) (list my-var) (mapcar (lambda (ele) (* 2 ele)) my-var)) + ⇒ '(8) + (-as-> 3 my-var 1+) + ⇒ 4 + (-as-> 3 my-var) + ⇒ 3 + + -- Macro: -some-> (x &optional form &rest more) + When expr is non-nil, thread it through the first form (via ‘->’ + (*note ->::)), and when that result is non-nil, through the next + form, etc. + + (-some-> '(2 3 5)) + ⇒ '(2 3 5) + (-some-> 5 square) + ⇒ 25 + (-some-> 5 even? square) + ⇒ nil + + -- Macro: -some->> (x &optional form &rest more) + When expr is non-nil, thread it through the first form (via ‘->>’ + (*note ->>::)), and when that result is non-nil, through the next + form, etc. + + (-some->> '(1 2 3) (-map 'square)) + ⇒ '(1 4 9) + (-some->> '(1 3 5) (-last 'even?) (+ 100)) + ⇒ nil + (-some->> '(2 4 6) (-last 'even?) (+ 100)) + ⇒ 106 + + -- Macro: -some--> (x &optional form &rest more) + When expr in non-nil, thread it through the first form (via ‘-->’ + (*note -->::)), and when that result is non-nil, through the next + form, etc. + + (-some--> "def" (concat "abc" it "ghi")) + ⇒ "abcdefghi" + (-some--> nil (concat "abc" it "ghi")) + ⇒ nil + (-some--> '(1 3 5) (-filter 'even? it) (append it it) (-map 'square it)) + ⇒ nil + + +File: dash.info, Node: Binding, Next: Side-effects, Prev: Threading macros, Up: Functions + +2.13 Binding +============ + +Convenient versions of ‘let‘ and ‘let*‘ constructs combined with flow +control. + + -- Macro: -when-let (var-val &rest body) + If VAL evaluates to non-nil, bind it to VAR and execute body. + + Note: binding is done according to ‘-let’ (*note -let::). + + (fn (VAR VAL) &rest BODY) + + (-when-let (match-index (string-match "d" "abcd")) (+ match-index 2)) + ⇒ 5 + (-when-let ((&plist :foo foo) (list :foo "foo")) foo) + ⇒ "foo" + (-when-let ((&plist :foo foo) (list :bar "bar")) foo) + ⇒ nil + + -- Macro: -when-let* (vars-vals &rest body) + If all VALS evaluate to true, bind them to their corresponding VARS + and execute body. VARS-VALS should be a list of (VAR VAL) pairs. + + Note: binding is done according to ‘-let*’ (*note -let*::). VALS + are evaluated sequentially, and evaluation stops after the first + nil VAL is encountered. + + (-when-let* ((x 5) (y 3) (z (+ y 4))) (+ x y z)) + ⇒ 15 + (-when-let* ((x 5) (y nil) (z 7)) (+ x y z)) + ⇒ nil + + -- Macro: -if-let (var-val then &rest else) + If VAL evaluates to non-nil, bind it to VAR and do THEN, otherwise + do ELSE. + + Note: binding is done according to ‘-let’ (*note -let::). + + (fn (VAR VAL) THEN &rest ELSE) + + (-if-let (match-index (string-match "d" "abc")) (+ match-index 3) 7) + ⇒ 7 + (--if-let (even? 4) it nil) + ⇒ t + + -- Macro: -if-let* (vars-vals then &rest else) + If all VALS evaluate to true, bind them to their corresponding VARS + and do THEN, otherwise do ELSE. VARS-VALS should be a list of (VAR + VAL) pairs. + + Note: binding is done according to ‘-let*’ (*note -let*::). VALS + are evaluated sequentially, and evaluation stops after the first + nil VAL is encountered. + + (-if-let* ((x 5) (y 3) (z 7)) (+ x y z) "foo") + ⇒ 15 + (-if-let* ((x 5) (y nil) (z 7)) (+ x y z) "foo") + ⇒ "foo" + (-if-let* (((_ _ x) '(nil nil 7))) x) + ⇒ 7 + + -- Macro: -let (varlist &rest body) + Bind variables according to VARLIST then eval BODY. + + VARLIST is a list of lists of the form (PATTERN SOURCE). Each + PATTERN is matched against the SOURCE "structurally". SOURCE is + only evaluated once for each PATTERN. Each PATTERN is matched + recursively, and can therefore contain sub-patterns which are + matched against corresponding sub-expressions of SOURCE. + + All the SOURCEs are evalled before any symbols are bound (i.e. "in + parallel"). + + If VARLIST only contains one (PATTERN SOURCE) element, you can + optionally specify it using a vector and discarding the outer-most + parens. Thus + + (-let ((PATTERN SOURCE)) ..) + + becomes + + (-let [PATTERN SOURCE] ..). + + ‘-let’ (*note -let::) uses a convention of not binding places + (symbols) starting with _ whenever it’s possible. You can use this + to skip over entries you don’t care about. However, this is not + *always* possible (as a result of implementation) and these symbols + might get bound to undefined values. + + Following is the overview of supported patterns. Remember that + patterns can be matched recursively, so every a, b, aK in the + following can be a matching construct and not necessarily a + symbol/variable. + + Symbol: + + a - bind the SOURCE to A. This is just like regular ‘let’. + + Conses and lists: + + (a) - bind ‘car’ of cons/list to A + + (a . b) - bind car of cons to A and ‘cdr’ to B + + (a b) - bind car of list to A and ‘cadr’ to B + + (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 + ... + + (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to + REST. + + Vectors: + + [a] - bind 0th element of a non-list sequence to A (works with + vectors, strings, bit arrays...) + + [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st + to A1, 2nd to A2, ... If the PATTERN is shorter than SOURCE, the + values at places not in PATTERN are ignored. If the PATTERN is + longer than SOURCE, an ‘error’ is thrown. + + [a1 a2 a3 ... &rest rest] - as above, but bind the rest of the + sequence to REST. This is conceptually the same as improper list + matching (a1 a2 ... aN . rest) + + Key/value stores: + + (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE plist to aK. If the value is not found, aK is nil. Uses + ‘plist-get’ to fetch values. + + (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE alist to aK. If the value is not found, aK is nil. Uses + ‘assoc’ to fetch values. + + (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE hash table to aK. If the value is not found, aK is nil. + Uses ‘gethash’ to fetch values. + + Further, special keyword &keys supports "inline" matching of + plist-like key-value pairs, similarly to &keys keyword of + ‘cl-defun’. + + (a1 a2 ... aN &keys key1 b1 ... keyN bK) + + This binds N values from the list to a1 ... aN, then interprets + the cdr as a plist (see key/value matching above). + + A shorthand notation for kv-destructuring exists which allows the + patterns be optionally left out and derived from the key name in + the following fashion: + + - a key :foo is converted into ‘foo’ pattern, - a key ’bar is + converted into ‘bar’ pattern, - a key "baz" is converted into ‘baz’ + pattern. + + That is, the entire value under the key is bound to the derived + variable without any further destructuring. + + This is possible only when the form following the key is not a + valid pattern (i.e. not a symbol, a cons cell or a vector). + Otherwise the matching proceeds as usual and in case of an invalid + spec fails with an error. + + Thus the patterns are normalized as follows: + + ;; derive all the missing patterns (&plist :foo ’bar "baz") => + (&plist :foo foo ’bar bar "baz" baz) + + ;; we can specify some but not others (&plist :foo ’bar + explicit-bar) => (&plist :foo foo ’bar explicit-bar) + + ;; nothing happens, we store :foo in x (&plist :foo x) => (&plist + :foo x) + + ;; nothing happens, we match recursively (&plist :foo (a b c)) => + (&plist :foo (a b c)) + + You can name the source using the syntax SYMBOL &as PATTERN. This + syntax works with lists (proper or improper), vectors and all types + of maps. + + (list &as a b c) (list 1 2 3) + + binds A to 1, B to 2, C to 3 and LIST to (1 2 3). + + Similarly: + + (bounds &as beg . end) (cons 1 2) + + binds BEG to 1, END to 2 and BOUNDS to (1 . 2). + + (items &as first . rest) (list 1 2 3) + + binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3) + + [vect &as _ b c] [1 2 3] + + binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as + usual). + + (plist &as &plist :b b) (list :a 1 :b 2 :c 3) + + binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and + &hash. + + This is especially useful when we want to capture the result of a + computation and destructure at the same time. Consider the form + (function-returning-complex-structure) returning a list of two + vectors with two items each. We want to capture this entire result + and pass it to another computation, but at the same time we want to + get the second item from each vector. We can achieve it with + pattern + + (result &as [_ a] [_ b]) (function-returning-complex-structure) + + Note: Clojure programmers may know this feature as the ":as + binding". The difference is that we put the &as at the front + because we need to support improper list binding. + + (-let (([a (b c) d] [1 (2 3) 4])) (list a b c d)) + ⇒ '(1 2 3 4) + (-let [(a b c . d) (list 1 2 3 4 5 6)] (list a b c d)) + ⇒ '(1 2 3 (4 5 6)) + (-let [(&plist :foo foo :bar bar) (list :baz 3 :foo 1 :qux 4 :bar 2)] (list foo bar)) + ⇒ '(1 2) + + -- Macro: -let* (varlist &rest body) + Bind variables according to VARLIST then eval BODY. + + VARLIST is a list of lists of the form (PATTERN SOURCE). Each + PATTERN is matched against the SOURCE structurally. SOURCE is only + evaluated once for each PATTERN. + + Each SOURCE can refer to the symbols already bound by this VARLIST. + This is useful if you want to destructure SOURCE recursively but + also want to name the intermediate structures. + + See ‘-let’ (*note -let::) for the list of all possible patterns. + + (-let* (((a . b) (cons 1 2)) ((c . d) (cons 3 4))) (list a b c d)) + ⇒ '(1 2 3 4) + (-let* (((a . b) (cons 1 (cons 2 3))) ((c . d) b)) (list a b c d)) + ⇒ '(1 (2 . 3) 2 3) + (-let* (((&alist "foo" foo "bar" bar) (list (cons "foo" 1) (cons "bar" (list 'a 'b 'c)))) ((a b c) bar)) (list foo a b c bar)) + ⇒ '(1 a b c (a b c)) + + -- Macro: -lambda (match-form &rest body) + Return a lambda which destructures its input as MATCH-FORM and + executes BODY. + + Note that you have to enclose the MATCH-FORM in a pair of parens, + such that: + + (-lambda (x) body) (-lambda (x y ...) body) + + has the usual semantics of ‘lambda’. Furthermore, these get + translated into normal lambda, so there is no performance penalty. + + See ‘-let’ (*note -let::) for the description of destructuring + mechanism. + + (-map (-lambda ((x y)) (+ x y)) '((1 2) (3 4) (5 6))) + ⇒ '(3 7 11) + (-map (-lambda ([x y]) (+ x y)) '([1 2] [3 4] [5 6])) + ⇒ '(3 7 11) + (funcall (-lambda ((_ . a) (_ . b)) (-concat a b)) '(1 2 3) '(4 5 6)) + ⇒ '(2 3 5 6) + + -- Macro: -setq (&rest forms) + Bind each MATCH-FORM to the value of its VAL. + + MATCH-FORM destructuring is done according to the rules of ‘-let’ + (*note -let::). + + This macro allows you to bind multiple variables by destructuring + the value, so for example: + + (-setq (a b) x (&plist :c c) plist) + + expands roughly speaking to the following code + + (setq a (car x) b (cadr x) c (plist-get plist :c)) + + Care is taken to only evaluate each VAL once so that in case of + multiple assignments it does not cause unexpected side effects. + + (fn [MATCH-FORM VAL]...) + + (progn (-setq a 1) a) + ⇒ 1 + (progn (-setq (a b) (list 1 2)) (list a b)) + ⇒ '(1 2) + (progn (-setq (&plist :c c) (list :c "c")) c) + ⇒ "c" + + +File: dash.info, Node: Side-effects, Next: Destructive operations, Prev: Binding, Up: Functions + +2.14 Side-effects +================= + +Functions iterating over lists for side-effect only. + + -- Function: -each (list fn) + Call FN with every item in LIST. Return nil, used for side-effects + only. + + (let (s) (-each '(1 2 3) (lambda (item) (setq s (cons item s))))) + ⇒ nil + (let (s) (-each '(1 2 3) (lambda (item) (setq s (cons item s)))) s) + ⇒ '(3 2 1) + (let (s) (--each '(1 2 3) (setq s (cons it s))) s) + ⇒ '(3 2 1) + + -- Function: -each-while (list pred fn) + Call FN with every item in LIST while (PRED item) is non-nil. + Return nil, used for side-effects only. + + (let (s) (-each-while '(2 4 5 6) 'even? (lambda (item) (!cons item s))) s) + ⇒ '(4 2) + (let (s) (--each-while '(1 2 3 4) (< it 3) (!cons it s)) s) + ⇒ '(2 1) + + -- Function: -each-indexed (list fn) + Call (FN index item) for each item in LIST. + + In the anaphoric form ‘--each-indexed’, the index is exposed as + symbol ‘it-index’. + + See also: ‘-map-indexed’ (*note -map-indexed::). + + (let (s) (-each-indexed '(a b c) (lambda (index item) (setq s (cons (list item index) s)))) s) + ⇒ '((c 2) (b 1) (a 0)) + (let (s) (--each-indexed '(a b c) (setq s (cons (list it it-index) s))) s) + ⇒ '((c 2) (b 1) (a 0)) + + -- Function: -each-r (list fn) + Call FN with every item in LIST in reversed order. Return nil, + used for side-effects only. + + (let (s) (-each-r '(1 2 3) (lambda (item) (setq s (cons item s))))) + ⇒ nil + (let (s) (-each-r '(1 2 3) (lambda (item) (setq s (cons item s)))) s) + ⇒ '(1 2 3) + (let (s) (--each-r '(1 2 3) (setq s (cons it s))) s) + ⇒ '(1 2 3) + + -- Function: -each-r-while (list pred fn) + Call FN with every item in reversed LIST while (PRED item) is + non-nil. Return nil, used for side-effects only. + + (let (s) (-each-r-while '(2 4 5 6) 'even? (lambda (item) (!cons item s))) s) + ⇒ '(6) + (let (s) (--each-r-while '(1 2 3 4) (>= it 3) (!cons it s)) s) + ⇒ '(3 4) + + -- Function: -dotimes (num fn) + Repeatedly calls FN (presumably for side-effects) passing in + integers from 0 through NUM-1. + + (let (s) (-dotimes 3 (lambda (n) (!cons n s))) s) + ⇒ '(2 1 0) + (let (s) (--dotimes 5 (!cons it s)) s) + ⇒ '(4 3 2 1 0) + + -- Macro: -doto (eval-initial-value &rest forms) + Eval a form, then insert that form as the 2nd argument to other + forms. The EVAL-INITIAL-VALUE form is evaluated once. Its result + is passed to FORMS, which are then evaluated sequentially. Returns + the target form. + + (-doto '(1 2 3) (!cdr) (!cdr)) + ⇒ '(3) + (-doto '(1 . 2) (setcar 3) (setcdr 4)) + ⇒ '(3 . 4) + + -- Macro: --doto (eval-initial-value &rest forms) + Anaphoric form of ‘-doto’ (*note -doto::). Note: ‘it’ is not + required in each form. + + (gethash "key" (--doto (make-hash-table :test 'equal) (puthash "key" "value" it))) + ⇒ "value" + + +File: dash.info, Node: Destructive operations, Next: Function combinators, Prev: Side-effects, Up: Functions + +2.15 Destructive operations +=========================== + + -- Macro: !cons (car cdr) + Destructive: Set CDR to the cons of CAR and CDR. + + (let (l) (!cons 5 l) l) + ⇒ '(5) + (let ((l '(3))) (!cons 5 l) l) + ⇒ '(5 3) + + -- Macro: !cdr (list) + Destructive: Set LIST to the cdr of LIST. + + (let ((l '(3))) (!cdr l) l) + ⇒ '() + (let ((l '(3 5))) (!cdr l) l) + ⇒ '(5) + + +File: dash.info, Node: Function combinators, Prev: Destructive operations, Up: Functions + +2.16 Function combinators +========================= + +These combinators require Emacs 24 for its lexical scope. So they are +offered in a separate package: ‘dash-functional‘. + + -- Function: -partial (fn &rest args) + Takes a function FN and fewer than the normal arguments to FN, and + returns a fn that takes a variable number of additional ARGS. When + called, the returned function calls FN with ARGS first and then + additional args. + + (funcall (-partial '- 5) 3) + ⇒ 2 + (funcall (-partial '+ 5 2) 3) + ⇒ 10 + + -- Function: -rpartial (fn &rest args) + Takes a function FN and fewer than the normal arguments to FN, and + returns a fn that takes a variable number of additional ARGS. When + called, the returned function calls FN with the additional args + first and then ARGS. + + (funcall (-rpartial '- 5) 8) + ⇒ 3 + (funcall (-rpartial '- 5 2) 10) + ⇒ 3 + + -- Function: -juxt (&rest fns) + Takes a list of functions and returns a fn that is the + juxtaposition of those fns. The returned fn takes a variable + number of args, and returns a list containing the result of + applying each fn to the args (left-to-right). + + (funcall (-juxt '+ '-) 3 5) + ⇒ '(8 -2) + (-map (-juxt 'identity 'square) '(1 2 3)) + ⇒ '((1 1) (2 4) (3 9)) + + -- Function: -compose (&rest fns) + Takes a list of functions and returns a fn that is the composition + of those fns. The returned fn takes a variable number of + arguments, and returns the result of applying each fn to the result + of applying the previous fn to the arguments (right-to-left). + + (funcall (-compose 'square '+) 2 3) + ⇒ (square (+ 2 3)) + (funcall (-compose 'identity 'square) 3) + ⇒ (square 3) + (funcall (-compose 'square 'identity) 3) + ⇒ (square 3) + + -- Function: -applify (fn) + Changes an n-arity function FN to a 1-arity function that expects a + list with n items as arguments + + (-map (-applify '+) '((1 1 1) (1 2 3) (5 5 5))) + ⇒ '(3 6 15) + (-map (-applify (lambda (a b c) `(,a (,b (,c))))) '((1 1 1) (1 2 3) (5 5 5))) + ⇒ '((1 (1 (1))) (1 (2 (3))) (5 (5 (5)))) + (funcall (-applify '<) '(3 6)) + ⇒ t + + -- Function: -on (operator transformer) + Return a function of two arguments that first applies TRANSFORMER + to each of them and then applies OPERATOR on the results (in the + same order). + + In types: (b -> b -> c) -> (a -> b) -> a -> a -> c + + (-sort (-on '< 'length) '((1 2 3) (1) (1 2))) + ⇒ '((1) (1 2) (1 2 3)) + (-min-by (-on '> 'length) '((1 2 3) (4) (1 2))) + ⇒ '(4) + (-min-by (-on 'string-lessp 'number-to-string) '(2 100 22)) + ⇒ 22 + + -- Function: -flip (func) + Swap the order of arguments for binary function FUNC. + + In types: (a -> b -> c) -> b -> a -> c + + (funcall (-flip '<) 2 1) + ⇒ t + (funcall (-flip '-) 3 8) + ⇒ 5 + (-sort (-flip '<) '(4 3 6 1)) + ⇒ '(6 4 3 1) + + -- Function: -const (c) + Return a function that returns C ignoring any additional arguments. + + In types: a -> b -> a + + (funcall (-const 2) 1 3 "foo") + ⇒ 2 + (-map (-const 1) '("a" "b" "c" "d")) + ⇒ '(1 1 1 1) + (-sum (-map (-const 1) '("a" "b" "c" "d"))) + ⇒ 4 + + -- Macro: -cut (&rest params) + Take n-ary function and n arguments and specialize some of them. + Arguments denoted by <> will be left unspecialized. + + See SRFI-26 for detailed description. + + (funcall (-cut list 1 <> 3 <> 5) 2 4) + ⇒ '(1 2 3 4 5) + (-map (-cut funcall <> 5) '(1+ 1- (lambda (x) (/ 1.0 x)))) + ⇒ '(6 4 0.2) + (-map (-cut <> 1 2 3) (list 'list 'vector 'string)) + ⇒ '((1 2 3) [1 2 3] "") + + -- Function: -not (pred) + Take a unary predicate PRED and return a unary predicate that + returns t if PRED returns nil and nil if PRED returns non-nil. + + (funcall (-not 'even?) 5) + ⇒ t + (-filter (-not (-partial '< 4)) '(1 2 3 4 5 6 7 8)) + ⇒ '(1 2 3 4) + + -- Function: -orfn (&rest preds) + Take list of unary predicates PREDS and return a unary predicate + with argument x that returns non-nil if at least one of the PREDS + returns non-nil on x. + + In types: [a -> Bool] -> a -> Bool + + (-filter (-orfn 'even? (-partial (-flip '<) 5)) '(1 2 3 4 5 6 7 8 9 10)) + ⇒ '(1 2 3 4 6 8 10) + (funcall (-orfn 'stringp 'even?) "foo") + ⇒ t + + -- Function: -andfn (&rest preds) + Take list of unary predicates PREDS and return a unary predicate + with argument x that returns non-nil if all of the PREDS returns + non-nil on x. + + In types: [a -> Bool] -> a -> Bool + + (funcall (-andfn (-cut < <> 10) 'even?) 6) + ⇒ t + (funcall (-andfn (-cut < <> 10) 'even?) 12) + ⇒ nil + (-filter (-andfn (-not 'even?) (-cut >= 5 <>)) '(1 2 3 4 5 6 7 8 9 10)) + ⇒ '(1 3 5) + + -- Function: -iteratefn (fn n) + Return a function FN composed N times with itself. + + FN is a unary function. If you need to use a function of higher + arity, use ‘-applify’ (*note -applify::) first to turn it into a + unary function. + + With n = 0, this acts as identity function. + + In types: (a -> a) -> Int -> a -> a. + + This function satisfies the following law: + + (funcall (-iteratefn fn n) init) = (-last-item (-iterate fn init + (1+ n))). + + (funcall (-iteratefn (lambda (x) (* x x)) 3) 2) + ⇒ 256 + (funcall (-iteratefn '1+ 3) 1) + ⇒ 4 + (funcall (-iteratefn 'cdr 3) '(1 2 3 4 5)) + ⇒ '(4 5) + + -- Function: -fixfn (fn &optional equal-test halt-test) + Return a function that computes the (least) fixpoint of FN. + + FN must be a unary function. The returned lambda takes a single + argument, X, the initial value for the fixpoint iteration. The + iteration halts when either of the following conditions is + satisfied: + + 1. Iteration converges to the fixpoint, with equality being tested + using EQUAL-TEST. If EQUAL-TEST is not specified, ‘equal’ is used. + For functions over the floating point numbers, it may be necessary + to provide an appropriate approximate comparison test. + + 2. HALT-TEST returns a non-nil value. HALT-TEST defaults to a + simple counter that returns t after ‘-fixfn-max-iterations’, to + guard against infinite iteration. Otherwise, HALT-TEST must be a + function that accepts a single argument, the current value of X, + and returns non-nil as long as iteration should continue. In this + way, a more sophisticated convergence test may be supplied by the + caller. + + The return value of the lambda is either the fixpoint or, if + iteration halted before converging, a cons with car ‘halted’ and + cdr the final output from HALT-TEST. + + In types: (a -> a) -> a -> a. + + (funcall (-fixfn 'cos 'approx-equal) 0.7) + ⇒ 0.7390851332151607 + (funcall (-fixfn (lambda (x) (expt (+ x 10) 0.25))) 2.0) + ⇒ 1.8555845286409378 + (funcall (-fixfn 'sin 'approx-equal) 0.1) + ⇒ '(halted . t) + + -- Function: -prodfn (&rest fns) + Take a list of n functions and return a function that takes a list + of length n, applying i-th function to i-th element of the input + list. Returns a list of length n. + + In types (for n=2): ((a -> b), (c -> d)) -> (a, c) -> (b, d) + + This function satisfies the following laws: + + (-compose (-prodfn f g ...) (-prodfn f’ g’ ...)) = (-prodfn + (-compose f f’) (-compose g g’) ...) (-prodfn f g ...) = (-juxt + (-compose f (-partial ’nth 0)) (-compose g (-partial ’nth 1)) ...) + (-compose (-prodfn f g ...) (-juxt f’ g’ ...)) = (-juxt (-compose + f f’) (-compose g g’) ...) (-compose (-partial ’nth n) (-prod f1 + f2 ...)) = (-compose fn (-partial ’nth n)) + + (funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3)) + ⇒ '(2 1 "3") + (-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8))) + ⇒ '((2 1) (4 3) (6 5) (8 7)) + (apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15"))) + ⇒ 18 + + +File: dash.info, Node: Development, Next: Index, Prev: Functions, Up: Top + +3 Development +************* + +The dash repository is hosted on GitHub: +<https://github.com/magnars/dash.el> + +* Menu: + +* Contribute:: How to contribute +* Changes:: List of significant changes by version +* Contributors:: List of contributors + + +File: dash.info, Node: Contribute, Next: Changes, Up: Development + +3.1 Contribute +============== + +Yes, please do. Pure functions in the list manipulation realm only, +please. There’s a suite of tests in dev/examples.el, so remember to add +tests for your function, or it might get broken later. + + Run the tests with ‘./run-tests.sh’. Create the docs with +‘./create-docs.sh’. I highly recommend that you install these as a +pre-commit hook, so that the tests are always running and the docs are +always in sync: + +cp pre-commit.sh .git/hooks/pre-commit + + Oh, and don’t edit ‘README.md’ directly, it is auto-generated. +Change ‘readme-template.md’ or ‘examples-to-docs.el’ instead. The same +goes for the info manual. + + +File: dash.info, Node: Changes, Next: Contributors, Prev: Contribute, Up: Development + +3.2 Changes +=========== + +Changes in 2.10: + + • Add ‘-let’ destructuring to ‘-if-let’ and ‘-when-let’ (Fredrik + Bergroth) + +Changes in 2.9: + + • Add ‘-let’, ‘-let*’ and ‘-lambda’ with destructuring + • Add ‘-tree-seq’ and ‘-tree-map-nodes’ + • Add ‘-non-nil’ + • Add ‘-fix’ + • Add ‘-fixfn’ (dash-functional 1.2) + • Add ‘-copy’ (Wilfred Hughes) + +Changes in 2.8: + + • Add ‘-butlast’ + +Changes in 2.7: + + • ‘-zip’ now supports more than two lists (Steve Lamb) + • Add ‘-cycle’, ‘-pad’, ‘-annotate’, ‘-zip-fill’ (Steve Lamb) + • Add ‘-table’, ‘-table-flat’ (finite cartesian product) + • Add ‘-flatten-n’ + • ‘-slice’ now supports "step" argument + • Add functional combinators ‘-iteratefn’, ‘-prodfn’ + • Add ‘-replace’, ‘-splice’, ‘-splice-list’ which generalize + ‘-replace-at’ and ‘-insert-at’ + • Add ‘-compose’, ‘-iteratefn’ and ‘-prodfn’ (dash-functional 1.1) + +Changes in 2.6: + + • Add ‘-is-prefix-p’, ‘-is-suffix-p’, ‘-is-infix-p’ (Matus Goljer) + • Add ‘-iterate’, ‘-unfold’ (Matus Goljer) + • Add ‘-split-on’, ‘-split-when’ (Matus Goljer) + • Add ‘-find-last-index’ (Matus Goljer) + • Add ‘-list’ (Johan Andersson) + +Changes in 2.5: + + • Add ‘-same-items?’ (Johan Andersson) + • A few bugfixes + +Changes in 2.4: + + • Add ‘-snoc’ (Matus Goljer) + • Add ‘-replace-at’, ‘-update-at’, ‘-remove-at’, and + ‘-remove-at-indices’ (Matus Goljer) + +Changes in 2.3: + + • Add tree operations (Matus Goljer) + • Make font-lock optional + +Changes in 2.2: + + • Add ‘-compose’ (Christina Whyte) + +Changes in 2.1: + + • Add indexing operations (Matus Goljer) + +Changes in 2.0: + + • Split out ‘dash-functional.el’ (Matus Goljer) + • Add ‘-andfn’, ‘-orfn’, ‘-not’, ‘-cut’, ‘-const’, ‘-flip’ and ‘-on’. + (Matus Goljer) + • Fix ‘-min’, ‘-max’, ‘-min-by’ and ‘-max-by’ (Matus Goljer) + +Changes in 1.8: + + • Add ‘-first-item’ and ‘-last-item’ (Wilfred Hughes) + +Changes in 1.7: + + • Add ‘-rotate’ (Matus Goljer) + +Changes in 1.6: + + • Add ‘-min’, ‘-max’, ‘-min-by’ and ‘-max-by’ (Johan Andersson) + +Changes in 1.5: + + • Add ‘-sum’ and ‘-product’ (Johan Andersson) + +Changes in 1.4: + + • Add ‘-sort’ + • Add ‘-reduce-r’ (Matus Goljer) + • Add ‘-reduce-r-from’ (Matus Goljer) + +Changes in 1.3: + + • Add ‘-partition-in-steps’ + • Add ‘-partition-all-in-steps’ + +Changes in 1.2: + + • Add ‘-last’ (Matus Goljer) + • Add ‘-insert-at’ (Emanuel Evans) + • Add ‘-when-let’ and ‘-if-let’ (Emanuel Evans) + • Add ‘-when-let*’ and ‘-if-let*’ (Emanuel Evans) + • Some bugfixes + + +File: dash.info, Node: Contributors, Prev: Changes, Up: Development + +3.3 Contributors +================ + + • Matus Goljer (https://github.com/Fuco1) contributed lots of + features and functions. + • Takafumi Arakaki (https://github.com/tkf) contributed ‘-group-by’. + • tali713 (https://github.com/tali713) is the author of ‘-applify’. + • Víctor M. Valenzuela (https://github.com/vemv) contributed + ‘-repeat’. + • Nic Ferrier (https://github.com/nicferrier) contributed ‘-cons*’. + • Wilfred Hughes (https://github.com/Wilfred) contributed ‘-slice’, + ‘-first-item’ and ‘-last-item’. + • Emanuel Evans (https://github.com/shosti) contributed ‘-if-let’, + ‘-when-let’ and ‘-insert-at’. + • Johan Andersson (https://github.com/rejeep) contributed ‘-sum’, + ‘-product’ and ‘-same-items?’ + • Christina Whyte (https://github.com/kurisuwhyte) contributed + ‘-compose’ + • Steve Lamb (https://github.com/steventlamb) contributed ‘-cycle’, + ‘-pad’, ‘-annotate’, ‘-zip-fill’ and an n-ary version of ‘-zip’. + • Fredrik Bergroth (https://github.com/fbergroth) made the ‘-if-let’ + family use ‘-let’ destructuring and improved script for generating + documentation. + • Mark Oteiza (https://github.com/holomorph) contributed the script + to create an info manual. + • Vasilij Schneidermann (https://github.com/wasamasa) contributed + ‘-some’. + • William West (https://github.com/occidens) made ‘-fixfn’ more + robust at handling floats. + + Thanks! + + +File: dash.info, Node: Index, Prev: Development, Up: Top + +Index +***** + + +* Menu: + +* !cdr: Destructive operations. + (line 14) +* !cons: Destructive operations. + (line 6) +* -->: Threading macros. (line 32) +* --doto: Side-effects. (line 81) +* ->: Threading macros. (line 6) +* ->>: Threading macros. (line 19) +* -all?: Predicates. (line 18) +* -andfn: Function combinators. + (line 138) +* -annotate: Maps. (line 79) +* -any?: Predicates. (line 6) +* -applify: Function combinators. + (line 55) +* -as->: Threading macros. (line 46) +* -butlast: Other list operations. + (line 340) +* -clone: Tree operations. (line 122) +* -common-prefix: Reductions. (line 223) +* -common-suffix: Reductions. (line 233) +* -compose: Function combinators. + (line 42) +* -concat: List to list. (line 22) +* -cons*: Other list operations. + (line 30) +* -const: Function combinators. + (line 92) +* -contains?: Predicates. (line 57) +* -copy: Maps. (line 134) +* -count: Reductions. (line 151) +* -cut: Function combinators. + (line 104) +* -cycle: Other list operations. + (line 168) +* -difference: Set operations. (line 20) +* -distinct: Set operations. (line 62) +* -dotimes: Side-effects. (line 61) +* -doto: Side-effects. (line 70) +* -drop: Sublist selection. (line 124) +* -drop-last: Sublist selection. (line 136) +* -drop-while: Sublist selection. (line 157) +* -each: Side-effects. (line 8) +* -each-indexed: Side-effects. (line 28) +* -each-r: Side-effects. (line 41) +* -each-r-while: Side-effects. (line 52) +* -each-while: Side-effects. (line 19) +* -elem-index: Indexing. (line 9) +* -elem-indices: Indexing. (line 21) +* -fifth-item: Other list operations. + (line 320) +* -filter: Sublist selection. (line 8) +* -find-index: Indexing. (line 32) +* -find-indices: Indexing. (line 60) +* -find-last-index: Indexing. (line 46) +* -first: Other list operations. + (line 234) +* -first-item: Other list operations. + (line 271) +* -fix: Other list operations. + (line 376) +* -fixfn: Function combinators. + (line 175) +* -flatten: List to list. (line 33) +* -flatten-n: List to list. (line 55) +* -flip: Function combinators. + (line 80) +* -fourth-item: Other list operations. + (line 310) +* -grade-down: Indexing. (line 81) +* -grade-up: Indexing. (line 71) +* -group-by: Partitioning. (line 187) +* -if-let: Binding. (line 36) +* -if-let*: Binding. (line 49) +* -inits: Reductions. (line 203) +* -insert-at: List to list. (line 109) +* -interleave: Other list operations. + (line 68) +* -interpose: Other list operations. + (line 58) +* -intersection: Set operations. (line 32) +* -is-infix?: Predicates. (line 110) +* -is-prefix?: Predicates. (line 86) +* -is-suffix?: Predicates. (line 98) +* -iterate: Unfolding. (line 9) +* -iteratefn: Function combinators. + (line 152) +* -juxt: Function combinators. + (line 31) +* -keep: List to list. (line 8) +* -lambda: Binding. (line 252) +* -last: Other list operations. + (line 261) +* -last-item: Other list operations. + (line 330) +* -let: Binding. (line 65) +* -let*: Binding. (line 232) +* -list: Other list operations. + (line 363) +* -map: Maps. (line 10) +* -map-first: Maps. (line 37) +* -map-indexed: Maps. (line 65) +* -map-last: Maps. (line 51) +* -map-when: Maps. (line 21) +* -mapcat: Maps. (line 123) +* -max: Reductions. (line 267) +* -max-by: Reductions. (line 277) +* -min: Reductions. (line 243) +* -min-by: Reductions. (line 253) +* -non-nil: Sublist selection. (line 79) +* -none?: Predicates. (line 30) +* -not: Function combinators. + (line 117) +* -on: Function combinators. + (line 66) +* -only-some?: Predicates. (line 42) +* -orfn: Function combinators. + (line 126) +* -pad: Other list operations. + (line 179) +* -partial: Function combinators. + (line 9) +* -partition: Partitioning. (line 74) +* -partition-after-item: Partitioning. (line 177) +* -partition-after-pred: Partitioning. (line 145) +* -partition-all: Partitioning. (line 86) +* -partition-all-in-steps: Partitioning. (line 109) +* -partition-before-item: Partitioning. (line 167) +* -partition-before-pred: Partitioning. (line 156) +* -partition-by: Partitioning. (line 121) +* -partition-by-header: Partitioning. (line 132) +* -partition-in-steps: Partitioning. (line 97) +* -permutations: Set operations. (line 52) +* -powerset: Set operations. (line 44) +* -prodfn: Function combinators. + (line 209) +* -product: Reductions. (line 181) +* -reduce: Reductions. (line 46) +* -reduce-from: Reductions. (line 8) +* -reduce-r: Reductions. (line 65) +* -reduce-r-from: Reductions. (line 27) +* -reductions: Reductions. (line 119) +* -reductions-from: Reductions. (line 87) +* -reductions-r: Reductions. (line 135) +* -reductions-r-from: Reductions. (line 103) +* -remove: Sublist selection. (line 23) +* -remove-at: List to list. (line 145) +* -remove-at-indices: List to list. (line 158) +* -remove-first: Sublist selection. (line 37) +* -remove-item: Sublist selection. (line 67) +* -remove-last: Sublist selection. (line 52) +* -repeat: Other list operations. + (line 19) +* -replace: List to list. (line 67) +* -replace-at: List to list. (line 120) +* -replace-first: List to list. (line 81) +* -replace-last: List to list. (line 95) +* -rotate: Other list operations. + (line 8) +* -rpartial: Function combinators. + (line 20) +* -running-product: Reductions. (line 191) +* -running-sum: Reductions. (line 169) +* -same-items?: Predicates. (line 72) +* -second-item: Other list operations. + (line 286) +* -select-by-indices: Sublist selection. (line 168) +* -select-column: Sublist selection. (line 198) +* -select-columns: Sublist selection. (line 179) +* -separate: Partitioning. (line 63) +* -setq: Binding. (line 274) +* -slice: Sublist selection. (line 85) +* -snoc: Other list operations. + (line 44) +* -some: Other list operations. + (line 248) +* -some-->: Threading macros. (line 83) +* -some->: Threading macros. (line 59) +* -some->>: Threading macros. (line 71) +* -sort: Other list operations. + (line 350) +* -splice: Maps. (line 90) +* -splice-list: Maps. (line 110) +* -split-at: Partitioning. (line 8) +* -split-on: Partitioning. (line 28) +* -split-when: Partitioning. (line 46) +* -split-with: Partitioning. (line 17) +* -sum: Reductions. (line 159) +* -table: Other list operations. + (line 190) +* -table-flat: Other list operations. + (line 209) +* -tails: Reductions. (line 213) +* -take: Sublist selection. (line 101) +* -take-last: Sublist selection. (line 112) +* -take-while: Sublist selection. (line 146) +* -third-item: Other list operations. + (line 298) +* -tree-map: Tree operations. (line 28) +* -tree-map-nodes: Tree operations. (line 39) +* -tree-mapreduce: Tree operations. (line 84) +* -tree-mapreduce-from: Tree operations. (line 103) +* -tree-reduce: Tree operations. (line 52) +* -tree-reduce-from: Tree operations. (line 69) +* -tree-seq: Tree operations. (line 8) +* -unfold: Unfolding. (line 25) +* -union: Set operations. (line 8) +* -unzip: Other list operations. + (line 146) +* -update-at: List to list. (line 132) +* -when-let: Binding. (line 9) +* -when-let*: Binding. (line 23) +* -zip: Other list operations. + (line 95) +* -zip-fill: Other list operations. + (line 138) +* -zip-lists: Other list operations. + (line 119) +* -zip-with: Other list operations. + (line 79) + + + +Tag Table: +Node: Top946 +Node: Installation2425 +Node: Using in a package2958 +Node: Syntax highlighting of dash functions3322 +Node: Functions3705 +Node: Maps4916 +Ref: -map5211 +Ref: -map-when5552 +Ref: -map-first6130 +Ref: -map-last6608 +Ref: -map-indexed7081 +Ref: -annotate7561 +Ref: -splice8051 +Ref: -splice-list8832 +Ref: -mapcat9294 +Ref: -copy9670 +Node: Sublist selection9874 +Ref: -filter10067 +Ref: -remove10519 +Ref: -remove-first10925 +Ref: -remove-last11452 +Ref: -remove-item11973 +Ref: -non-nil12368 +Ref: -slice12527 +Ref: -take13059 +Ref: -take-last13367 +Ref: -drop13690 +Ref: -drop-last13963 +Ref: -take-while14223 +Ref: -drop-while14573 +Ref: -select-by-indices14929 +Ref: -select-columns15443 +Ref: -select-column16149 +Node: List to list16613 +Ref: -keep16805 +Ref: -concat17308 +Ref: -flatten17605 +Ref: -flatten-n18364 +Ref: -replace18751 +Ref: -replace-first19214 +Ref: -replace-last19711 +Ref: -insert-at20201 +Ref: -replace-at20528 +Ref: -update-at20918 +Ref: -remove-at21409 +Ref: -remove-at-indices21897 +Node: Reductions22479 +Ref: -reduce-from22648 +Ref: -reduce-r-from23414 +Ref: -reduce24181 +Ref: -reduce-r24910 +Ref: -reductions-from25781 +Ref: -reductions-r-from26496 +Ref: -reductions27221 +Ref: -reductions-r27846 +Ref: -count28481 +Ref: -sum28705 +Ref: -running-sum28894 +Ref: -product29187 +Ref: -running-product29396 +Ref: -inits29709 +Ref: -tails29957 +Ref: -common-prefix30204 +Ref: -common-suffix30501 +Ref: -min30798 +Ref: -min-by31024 +Ref: -max31547 +Ref: -max-by31772 +Node: Unfolding32300 +Ref: -iterate32539 +Ref: -unfold32984 +Node: Predicates33792 +Ref: -any?33916 +Ref: -all?34236 +Ref: -none?34566 +Ref: -only-some?34868 +Ref: -contains?35353 +Ref: -same-items?35742 +Ref: -is-prefix?36127 +Ref: -is-suffix?36450 +Ref: -is-infix?36773 +Node: Partitioning37127 +Ref: -split-at37315 +Ref: -split-with37600 +Ref: -split-on38003 +Ref: -split-when38679 +Ref: -separate39319 +Ref: -partition39761 +Ref: -partition-all40213 +Ref: -partition-in-steps40641 +Ref: -partition-all-in-steps41138 +Ref: -partition-by41623 +Ref: -partition-by-header42005 +Ref: -partition-after-pred42609 +Ref: -partition-before-pred42953 +Ref: -partition-before-item43304 +Ref: -partition-after-item43615 +Ref: -group-by43921 +Node: Indexing44358 +Ref: -elem-index44560 +Ref: -elem-indices44955 +Ref: -find-index45338 +Ref: -find-last-index45827 +Ref: -find-indices46331 +Ref: -grade-up46739 +Ref: -grade-down47142 +Node: Set operations47552 +Ref: -union47735 +Ref: -difference48177 +Ref: -intersection48594 +Ref: -powerset49031 +Ref: -permutations49244 +Ref: -distinct49544 +Node: Other list operations49922 +Ref: -rotate50147 +Ref: -repeat50517 +Ref: -cons*50780 +Ref: -snoc51167 +Ref: -interpose51580 +Ref: -interleave51878 +Ref: -zip-with52247 +Ref: -zip52964 +Ref: -zip-lists53796 +Ref: -zip-fill54497 +Ref: -unzip54820 +Ref: -cycle55565 +Ref: -pad55938 +Ref: -table56261 +Ref: -table-flat57050 +Ref: -first58058 +Ref: -some58430 +Ref: -last58739 +Ref: -first-item59073 +Ref: -second-item59489 +Ref: -third-item59769 +Ref: -fourth-item60047 +Ref: -fifth-item60313 +Ref: -last-item60575 +Ref: -butlast60867 +Ref: -sort61114 +Ref: -list61603 +Ref: -fix61934 +Node: Tree operations62474 +Ref: -tree-seq62670 +Ref: -tree-map63528 +Ref: -tree-map-nodes63971 +Ref: -tree-reduce64821 +Ref: -tree-reduce-from65703 +Ref: -tree-mapreduce66304 +Ref: -tree-mapreduce-from67164 +Ref: -clone68450 +Node: Threading macros68778 +Ref: ->68923 +Ref: ->>69414 +Ref: -->69919 +Ref: -as->70475 +Ref: -some->70930 +Ref: -some->>71304 +Ref: -some-->71740 +Node: Binding72211 +Ref: -when-let72423 +Ref: -when-let*72908 +Ref: -if-let73431 +Ref: -if-let*73826 +Ref: -let74443 +Ref: -let*80533 +Ref: -lambda81473 +Ref: -setq82270 +Node: Side-effects83086 +Ref: -each83280 +Ref: -each-while83687 +Ref: -each-indexed84047 +Ref: -each-r84565 +Ref: -each-r-while84998 +Ref: -dotimes85373 +Ref: -doto85676 +Ref: --doto86104 +Node: Destructive operations86379 +Ref: !cons86552 +Ref: !cdr86758 +Node: Function combinators86953 +Ref: -partial87227 +Ref: -rpartial87623 +Ref: -juxt88026 +Ref: -compose88458 +Ref: -applify89011 +Ref: -on89442 +Ref: -flip89968 +Ref: -const90280 +Ref: -cut90619 +Ref: -not91105 +Ref: -orfn91415 +Ref: -andfn91849 +Ref: -iteratefn92344 +Ref: -fixfn93047 +Ref: -prodfn94610 +Node: Development95678 +Node: Contribute96027 +Node: Changes96775 +Node: Contributors99773 +Node: Index101392 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/elpa/dash-20200524.1947/dir b/elpa/dash-20200524.1947/dir new file mode 100644 index 0000000..49b1700 --- /dev/null +++ b/elpa/dash-20200524.1947/dir @@ -0,0 +1,18 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "H" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs<Return>" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* Dash: (dash.info). A modern list library for GNU Emacs |