From: Andreas Gerler Date: Thu, 30 May 2024 16:07:35 +0000 (+0200) Subject: update dash X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=aa7f2cdc998525776b29a6780b3c0a210b69fa7d;p=emacsconfig.git update dash Signed-off-by: Andreas Gerler --- diff --git a/elpa/dash-20230714.723/dash-autoloads.el b/elpa/dash-20230714.723/dash-autoloads.el deleted file mode 100644 index 6783a8d0..00000000 --- a/elpa/dash-20230714.723/dash-autoloads.el +++ /dev/null @@ -1,87 +0,0 @@ -;;; dash-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- -;; -;;; 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 - -(autoload 'dash-fontify-mode "dash" "\ -Toggle fontification of Dash special variables. - -This is a minor mode. If called interactively, toggle the -`Dash-Fontify mode' mode. If the prefix argument is positive, -enable the mode, and if it is zero or negative, disable the mode. - -If called from Lisp, toggle the mode if ARG is `toggle'. Enable -the mode if ARG is nil, omitted, or is a positive number. -Disable the mode if ARG is a negative number. - -To check whether the minor mode is enabled in the current buffer, -evaluate `dash-fontify-mode'. - -The mode's hook is called both when the mode is enabled and when -it is disabled. - -Dash-Fontify mode is a buffer-local minor mode intended for Emacs -Lisp buffers. Enabling it causes the special variables bound in -anaphoric Dash macros to be fontified. These anaphoras include -`it', `it-index', `acc', and `other'. In older Emacs versions -which do not dynamically detect macros, Dash-Fontify mode -additionally fontifies Dash macro calls. - -See also `dash-fontify-mode-lighter' and -`global-dash-fontify-mode'. - -\(fn &optional ARG)" t nil) - -(put 'global-dash-fontify-mode 'globalized-minor-mode t) - -(defvar global-dash-fontify-mode nil "\ -Non-nil if Global Dash-Fontify mode is enabled. -See the `global-dash-fontify-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `global-dash-fontify-mode'.") - -(custom-autoload 'global-dash-fontify-mode "dash" nil) - -(autoload 'global-dash-fontify-mode "dash" "\ -Toggle Dash-Fontify mode in all buffers. -With prefix ARG, enable Global Dash-Fontify mode if ARG is positive; -otherwise, disable it. - -If called from Lisp, toggle the mode if ARG is `toggle'. -Enable the mode if ARG is nil, omitted, or is a positive number. -Disable the mode if ARG is a negative number. - -Dash-Fontify mode is enabled in all buffers where -`dash--turn-on-fontify-mode' would do it. - -See `dash-fontify-mode' for more information on Dash-Fontify mode. - -\(fn &optional ARG)" t nil) - -(autoload 'dash-register-info-lookup "dash" "\ -Register the Dash Info manual with `info-lookup-symbol'. -This allows Dash symbols to be looked up with \\[info-lookup-symbol]." t nil) - -(register-definition-prefixes "dash" '("!cdr" "!cons" "--" "->" "-a" "-butlast" "-c" "-d" "-e" "-f" "-gr" "-i" "-juxt" "-keep" "-l" "-m" "-no" "-o" "-p" "-r" "-s" "-t" "-u" "-value-to-list" "-when-let" "-zip" "dash-")) - -;;;*** - -;;;### (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-20230714.723/dash-pkg.el b/elpa/dash-20230714.723/dash-pkg.el deleted file mode 100644 index e2592b7c..00000000 --- a/elpa/dash-20230714.723/dash-pkg.el +++ /dev/null @@ -1,14 +0,0 @@ -(define-package "dash" "20230714.723" "A modern list library for Emacs" - '((emacs "24")) - :commit "f46268c75cb7c18361d3cee942cd4dc14a03aef4" :authors - '(("Magnar Sveen" . "magnars@gmail.com")) - :maintainers - '(("Magnar Sveen" . "magnars@gmail.com")) - :maintainer - '("Magnar Sveen" . "magnars@gmail.com") - :keywords - '("extensions" "lisp") - :url "https://github.com/magnars/dash.el") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/dash-20230714.723/dash.el b/elpa/dash-20230714.723/dash.el deleted file mode 100644 index d9007175..00000000 --- a/elpa/dash-20230714.723/dash.el +++ /dev/null @@ -1,4134 +0,0 @@ -;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- - -;; Copyright (C) 2012-2023 Free Software Foundation, Inc. - -;; Author: Magnar Sveen -;; Version: 2.19.1 -;; Package-Requires: ((emacs "24")) -;; Keywords: extensions, lisp -;; Homepage: https://github.com/magnars/dash.el - -;; 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 . - -;;; Commentary: - -;; A modern list API for Emacs. -;; -;; See its overview at https://github.com/magnars/dash.el#functions. - -;;; Code: - -(eval-when-compile - ;; TODO: Emacs 24.3 first introduced `gv', so remove this and all - ;; calls to `defsetf' when support for earlier versions is dropped. - (unless (fboundp 'gv-define-setter) - (require 'cl)) - - ;; - 24.3 started complaining about unknown `declare' props. - ;; - 25 introduced `pure' and `side-effect-free'. - ;; - 30 introduced `important-return-value'. - (when (boundp 'defun-declarations-alist) - (dolist (prop '(important-return-value pure side-effect-free)) - (unless (assq prop defun-declarations-alist) - (push (list prop #'ignore) defun-declarations-alist))))) - -(defgroup dash () - "Customize group for Dash, a modern list library." - :group 'extensions - :group 'lisp - :prefix "dash-") - -(defmacro !cons (car cdr) - "Destructive: Set CDR to the cons of CAR and CDR." - (declare (debug (form symbolp))) - `(setq ,cdr (cons ,car ,cdr))) - -(defmacro !cdr (list) - "Destructive: Set LIST to the cdr of LIST." - (declare (debug (symbolp))) - `(setq ,list (cdr ,list))) - -(defmacro --each (list &rest body) - "Evaluate BODY for each element of LIST and return nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating BODY. -This is the anaphoric counterpart to `-each'." - (declare (debug (form body)) (indent 1)) - (let ((l (make-symbol "list")) - (i (make-symbol "i"))) - `(let ((,l ,list) - (,i 0)) - (while ,l - (let ((it (pop ,l)) (it-index ,i)) - (ignore it it-index) - ,@body) - (setq ,i (1+ ,i)))))) - -(defun -each (list fn) - "Call FN on each element of LIST. -Return nil; this function is intended for side effects. - -Its anaphoric counterpart is `--each'. - -For access to the current element's index in LIST, see -`-each-indexed'." - (declare (indent 1)) - (ignore (mapc fn list))) - -(defalias '--each-indexed '--each) - -(defun -each-indexed (list fn) - "Call FN on each index and element of LIST. -For each ITEM at INDEX in LIST, call (funcall FN INDEX ITEM). -Return nil; this function is intended for side effects. - -See also: `-map-indexed'." - (declare (indent 1)) - (--each list (funcall fn it-index it))) - -(defmacro --each-while (list pred &rest body) - "Evaluate BODY for each item in LIST, while PRED evaluates to non-nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating PRED or BODY. Once -an element is reached for which PRED evaluates to nil, no further -BODY is evaluated. The return value is always nil. -This is the anaphoric counterpart to `-each-while'." - (declare (debug (form form body)) (indent 2)) - (let ((l (make-symbol "list")) - (i (make-symbol "i")) - (elt (make-symbol "elt"))) - `(let ((,l ,list) - (,i 0) - ,elt) - (while (when ,l - (setq ,elt (car-safe ,l)) - (let ((it ,elt) (it-index ,i)) - (ignore it it-index) - ,pred)) - (let ((it ,elt) (it-index ,i)) - (ignore it it-index) - ,@body) - (setq ,i (1+ ,i) ,l (cdr ,l)))))) - -(defun -each-while (list pred fn) - "Call FN on each ITEM in LIST, while (PRED ITEM) is non-nil. -Once an ITEM is reached for which PRED returns nil, FN is no -longer called. Return nil; this function is intended for side -effects. - -Its anaphoric counterpart is `--each-while'." - (declare (indent 2)) - (--each-while list (funcall pred it) (funcall fn it))) - -(defmacro --each-r (list &rest body) - "Evaluate BODY for each element of LIST in reversed order. -Each element of LIST in turn, starting at its end, is bound to -`it' and its index within LIST to `it-index' before evaluating -BODY. The return value is always nil. -This is the anaphoric counterpart to `-each-r'." - (declare (debug (form body)) (indent 1)) - (let ((v (make-symbol "vector")) - (i (make-symbol "i"))) - ;; Implementation note: building a 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 the modification was undone before we return. - `(let* ((,v (vconcat ,list)) - (,i (length ,v)) - it it-index) - (ignore it it-index) - (while (> ,i 0) - (setq ,i (1- ,i) it-index ,i it (aref ,v ,i)) - ,@body)))) - -(defun -each-r (list fn) - "Call FN on each element of LIST in reversed order. -Return nil; this function is intended for side effects. - -Its anaphoric counterpart is `--each-r'." - (--each-r list (funcall fn it))) - -(defmacro --each-r-while (list pred &rest body) - "Eval BODY for each item in reversed LIST, while PRED evals to non-nil. -Each element of LIST in turn, starting at its end, is bound to -`it' and its index within LIST to `it-index' before evaluating -PRED or BODY. Once an element is reached for which PRED -evaluates to nil, no further BODY is evaluated. The return value -is always nil. -This is the anaphoric counterpart to `-each-r-while'." - (declare (debug (form form body)) (indent 2)) - (let ((v (make-symbol "vector")) - (i (make-symbol "i")) - (elt (make-symbol "elt"))) - `(let* ((,v (vconcat ,list)) - (,i (length ,v)) - ,elt it it-index) - (ignore it it-index) - (while (when (> ,i 0) - (setq ,i (1- ,i) it-index ,i) - (setq ,elt (aref ,v ,i) it ,elt) - ,pred) - (setq it-index ,i it ,elt) - ,@body)))) - -(defun -each-r-while (list pred fn) - "Call FN on each ITEM in reversed LIST, while (PRED ITEM) is non-nil. -Once an ITEM is reached for which PRED returns nil, FN is no -longer called. Return nil; this function is intended for side -effects. - -Its anaphoric counterpart is `--each-r-while'." - (--each-r-while list (funcall pred it) (funcall fn it))) - -(defmacro --dotimes (num &rest body) - "Evaluate BODY NUM times, presumably for side effects. -BODY is evaluated with the local variable `it' temporarily bound -to successive integers running from 0, inclusive, to NUM, -exclusive. BODY is not evaluated if NUM is less than 1. -This is the anaphoric counterpart to `-dotimes'." - (declare (debug (form body)) (indent 1)) - (let ((n (make-symbol "num")) - (i (make-symbol "i"))) - `(let ((,n ,num) - (,i 0) - it) - (ignore it) - (while (< ,i ,n) - (setq it ,i ,i (1+ ,i)) - ,@body)))) - -(defun -dotimes (num fn) - "Call FN NUM times, presumably for side effects. -FN is called with a single argument on successive integers -running from 0, inclusive, to NUM, exclusive. FN is not called -if NUM is less than 1. - -This function's anaphoric counterpart is `--dotimes'." - (declare (indent 1)) - (--dotimes num (funcall fn it))) - -(defun -map (fn list) - "Apply FN to each item in LIST and return the list of results. - -This function's anaphoric counterpart is `--map'." - (declare (important-return-value t)) - (mapcar fn list)) - -(defmacro --map (form list) - "Eval FORM for each item in LIST and return the list of results. -Each element of LIST in turn is bound to `it' before evaluating -FORM. -This is the anaphoric counterpart to `-map'." - (declare (debug (def-form form))) - `(mapcar (lambda (it) (ignore it) ,form) ,list)) - -(defmacro --reduce-from (form init list) - "Accumulate a value by evaluating FORM across LIST. -This macro is like `--each' (which see), but it additionally -provides an accumulator variable `acc' which it successively -binds to the result of evaluating FORM for the current LIST -element before processing the next element. For the first -element, `acc' is initialized with the result of evaluating INIT. -The return value is the resulting value of `acc'. If LIST is -empty, FORM is not evaluated, and the return value is the result -of INIT. -This is the anaphoric counterpart to `-reduce-from'." - (declare (debug (form form form))) - `(let ((acc ,init)) - (--each ,list (setq acc ,form)) - acc)) - -(defun -reduce-from (fn init list) - "Reduce the function FN across LIST, starting with INIT. -Return the result of applying FN to INIT and the first element of -LIST, then applying FN to that result and the second element, -etc. If LIST is empty, return INIT without calling FN. - -This function's anaphoric counterpart is `--reduce-from'. - -For other folds, see also `-reduce' and `-reduce-r'." - (declare (important-return-value t)) - (--reduce-from (funcall fn acc it) init list)) - -(defmacro --reduce (form list) - "Accumulate a value by evaluating FORM across LIST. -This macro is like `--reduce-from' (which see), except the first -element of LIST is taken as INIT. Thus if LIST contains a single -item, it is returned without evaluating FORM. If LIST is empty, -FORM is evaluated with `it' and `acc' bound to nil. -This is the anaphoric counterpart to `-reduce'." - (declare (debug (form form))) - (let ((lv (make-symbol "list-value"))) - `(let ((,lv ,list)) - (if ,lv - (--reduce-from ,form (car ,lv) (cdr ,lv)) - ;; Explicit nil binding pacifies lexical "variable left uninitialized" - ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. - (let ((acc nil) (it nil)) - (ignore acc it) - ,form))))) - -(defun -reduce (fn list) - "Reduce the function FN across LIST. -Return the result of applying FN to the first two elements of -LIST, then applying FN to that result and the third element, etc. -If LIST contains a single element, return it without calling FN. -If LIST is empty, return the result of calling FN with no -arguments. - -This function's anaphoric counterpart is `--reduce'. - -For other folds, see also `-reduce-from' and `-reduce-r'." - (declare (important-return-value t)) - (if list - (-reduce-from fn (car list) (cdr list)) - (funcall fn))) - -(defmacro --reduce-r-from (form init list) - "Accumulate a value by evaluating FORM across LIST in reverse. -This macro is like `--reduce-from', except it starts from the end -of LIST. -This is the anaphoric counterpart to `-reduce-r-from'." - (declare (debug (form form form))) - `(let ((acc ,init)) - (--each-r ,list (setq acc ,form)) - acc)) - -(defun -reduce-r-from (fn init list) - "Reduce the function FN across LIST in reverse, starting with INIT. -Return the result of applying FN to the last element of LIST and -INIT, then applying FN to the second-to-last element and the -previous result of FN, etc. That is, the first argument of FN is -the current element, and its second argument the accumulated -value. If LIST is empty, return INIT without calling FN. - -This function is like `-reduce-from' but the operation associates -from the right rather than left. In other words, it starts from -the end of LIST and flips the arguments to FN. Conceptually, it -is like replacing the conses in LIST with applications of FN, and -its last link with INIT, and evaluating the resulting expression. - -This function's anaphoric counterpart is `--reduce-r-from'. - -For other folds, see also `-reduce-r' and `-reduce'." - (declare (important-return-value t)) - (--reduce-r-from (funcall fn it acc) init list)) - -(defmacro --reduce-r (form list) - "Accumulate a value by evaluating FORM across LIST in reverse order. -This macro is like `--reduce', except it starts from the end of -LIST. -This is the anaphoric counterpart to `-reduce-r'." - (declare (debug (form form))) - `(--reduce ,form (reverse ,list))) - -(defun -reduce-r (fn list) - "Reduce the function FN across LIST in reverse. -Return the result of applying FN to the last two elements of -LIST, then applying FN to the third-to-last element and the -previous result of FN, etc. That is, the first argument of FN is -the current element, and its second argument the accumulated -value. If LIST contains a single element, return it without -calling FN. If LIST is empty, return the result of calling FN -with no arguments. - -This function is like `-reduce' but the operation associates from -the right rather than left. In other words, it starts from the -end of LIST and flips the arguments to FN. Conceptually, it is -like replacing the conses in LIST with applications of FN, -ignoring its last link, and evaluating the resulting expression. - -This function's anaphoric counterpart is `--reduce-r'. - -For other folds, see also `-reduce-r-from' and `-reduce'." - (declare (important-return-value t)) - (if list - (--reduce-r (funcall fn it acc) list) - (funcall fn))) - -(defmacro --reductions-from (form init list) - "Return a list of FORM's intermediate reductions across LIST. -That is, a list of the intermediate values of the accumulator -when `--reduce-from' (which see) is called with the same -arguments. -This is the anaphoric counterpart to `-reductions-from'." - (declare (debug (form form form))) - `(nreverse - (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) - (list ,init) - ,list))) - -(defun -reductions-from (fn init list) - "Return a list of FN's intermediate reductions across LIST. -That is, a list of the intermediate values of the accumulator -when `-reduce-from' (which see) is called with the same -arguments. - -This function's anaphoric counterpart is `--reductions-from'. - -For other folds, see also `-reductions' and `-reductions-r'." - (declare (important-return-value t)) - (--reductions-from (funcall fn acc it) init list)) - -(defmacro --reductions (form list) - "Return a list of FORM's intermediate reductions across LIST. -That is, a list of the intermediate values of the accumulator -when `--reduce' (which see) is called with the same arguments. -This is the anaphoric counterpart to `-reductions'." - (declare (debug (form form))) - (let ((lv (make-symbol "list-value"))) - `(let ((,lv ,list)) - (if ,lv - (--reductions-from ,form (car ,lv) (cdr ,lv)) - ;; Explicit nil binding pacifies lexical "variable left uninitialized" - ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. - (let ((acc nil) (it nil)) - (ignore acc it) - (list ,form)))))) - -(defun -reductions (fn list) - "Return a list of FN's intermediate reductions across LIST. -That is, a list of the intermediate values of the accumulator -when `-reduce' (which see) is called with the same arguments. - -This function's anaphoric counterpart is `--reductions'. - -For other folds, see also `-reductions' and `-reductions-r'." - (declare (important-return-value t)) - (if list - (--reductions-from (funcall fn acc it) (car list) (cdr list)) - (list (funcall fn)))) - -(defmacro --reductions-r-from (form init list) - "Return a list of FORM's intermediate reductions across reversed LIST. -That is, a list of the intermediate values of the accumulator -when `--reduce-r-from' (which see) is called with the same -arguments. -This is the anaphoric counterpart to `-reductions-r-from'." - (declare (debug (form form form))) - `(--reduce-r-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) - (list ,init) - ,list)) - -(defun -reductions-r-from (fn init list) - "Return a list of FN's intermediate reductions across reversed LIST. -That is, a list of the intermediate values of the accumulator -when `-reduce-r-from' (which see) is called with the same -arguments. - -This function's anaphoric counterpart is `--reductions-r-from'. - -For other folds, see also `-reductions' and `-reductions-r'." - (declare (important-return-value t)) - (--reductions-r-from (funcall fn it acc) init list)) - -(defmacro --reductions-r (form list) - "Return a list of FORM's intermediate reductions across reversed LIST. -That is, a list of the intermediate values of the accumulator -when `--reduce-re' (which see) is called with the same arguments. -This is the anaphoric counterpart to `-reductions-r'." - (declare (debug (form list))) - (let ((lv (make-symbol "list-value"))) - `(let ((,lv (reverse ,list))) - (if ,lv - (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) - (list (car ,lv)) - (cdr ,lv)) - ;; Explicit nil binding pacifies lexical "variable left uninitialized" - ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. - (let ((acc nil) (it nil)) - (ignore acc it) - (list ,form)))))) - -(defun -reductions-r (fn list) - "Return a list of FN's intermediate reductions across reversed LIST. -That is, a list of the intermediate values of the accumulator -when `-reduce-r' (which see) is called with the same arguments. - -This function's anaphoric counterpart is `--reductions-r'. - -For other folds, see also `-reductions-r-from' and -`-reductions'." - (declare (important-return-value t)) - (if list - (--reductions-r (funcall fn it acc) list) - (list (funcall fn)))) - -(defmacro --filter (form list) - "Return a new list of the items in LIST for which FORM evals to non-nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-filter'. -For the opposite operation, see also `--remove'." - (declare (debug (form form))) - (let ((r (make-symbol "result"))) - `(let (,r) - (--each ,list (when ,form (push it ,r))) - (nreverse ,r)))) - -(defun -filter (pred list) - "Return a new list of the items in LIST for which PRED returns non-nil. - -Alias: `-select'. - -This function's anaphoric counterpart is `--filter'. - -For similar operations, see also `-keep' and `-remove'." - (declare (important-return-value t)) - (--filter (funcall pred it) list)) - -(defalias '-select '-filter) -(defalias '--select '--filter) - -(defmacro --remove (form list) - "Return a new list of the items in LIST for which FORM evals to nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-remove'. -For the opposite operation, 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'. - -This function's anaphoric counterpart is `--remove'. - -For similar operations, see also `-keep' and `-filter'." - (declare (important-return-value t)) - (--remove (funcall pred it) list)) - -(defalias '-reject '-remove) -(defalias '--reject '--remove) - -(defmacro --remove-first (form list) - "Remove the first item from LIST for which FORM evals to non-nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. This is a -non-destructive operation, but only the front of LIST leading up -to the removed item is a copy; the rest is LIST's original tail. -If no item is removed, then the result is a complete copy. -This is the anaphoric counterpart to `-remove-first'." - (declare (debug (form form))) - (let ((front (make-symbol "front")) - (tail (make-symbol "tail"))) - `(let ((,tail ,list) ,front) - (--each-while ,tail (not ,form) - (push (pop ,tail) ,front)) - (if ,tail - (nconc (nreverse ,front) (cdr ,tail)) - (nreverse ,front))))) - -(defun -remove-first (pred list) - "Remove the first item from LIST for which PRED returns non-nil. -This is a non-destructive operation, but only the front of LIST -leading up to the removed item is a copy; the rest is LIST's -original tail. If no item is removed, then the result is a -complete copy. - -Alias: `-reject-first'. - -This function's anaphoric counterpart is `--remove-first'. - -See also `-map-first', `-remove-item', and `-remove-last'." - (declare (important-return-value t)) - (--remove-first (funcall pred it) list)) - -;; TODO: #'-quoting the macro upsets Emacs 24. -(defalias '-reject-first #'-remove-first) -(defalias '--reject-first '--remove-first) - -(defmacro --remove-last (form list) - "Remove the last item from LIST for which FORM evals to non-nil. -Each element of LIST in turn is bound to `it' before evaluating -FORM. The result is a copy of LIST regardless of whether an -element is removed. -This is the anaphoric counterpart to `-remove-last'." - (declare (debug (form form))) - `(nreverse (--remove-first ,form (reverse ,list)))) - -(defun -remove-last (pred list) - "Remove the last item from LIST for which PRED returns non-nil. -The result is a copy of LIST regardless of whether an element is -removed. - -Alias: `-reject-last'. - -This function's anaphoric counterpart is `--remove-last'. - -See also `-map-last', `-remove-item', and `-remove-first'." - (declare (important-return-value t)) - (--remove-last (funcall pred it) list)) - -(defalias '-reject-last '-remove-last) -(defalias '--reject-last '--remove-last) - -(defalias '-remove-item #'remove - "Return a copy of LIST with all occurrences of ITEM removed. -The comparison is done with `equal'. -\n(fn ITEM LIST)") - -(defmacro --keep (form list) - "Eval FORM for each item in LIST and return the non-nil results. -Like `--filter', but returns the non-nil results of FORM instead -of the corresponding elements of LIST. Each element of LIST in -turn is bound to `it' and its index within LIST to `it-index' -before evaluating FORM. -This is the anaphoric counterpart to `-keep'." - (declare (debug (form form))) - (let ((r (make-symbol "result")) - (m (make-symbol "mapped"))) - `(let (,r) - (--each ,list (let ((,m ,form)) (when ,m (push ,m ,r)))) - (nreverse ,r)))) - -(defun -keep (fn list) - "Return a new list of the non-nil results of applying FN to each item in LIST. -Like `-filter', but returns the non-nil results of FN instead of -the corresponding elements of LIST. - -Its anaphoric counterpart is `--keep'." - (declare (important-return-value t)) - (--keep (funcall fn it) list)) - -(defun -non-nil (list) - "Return a copy of LIST with all nil items removed." - (declare (side-effect-free t)) - (--filter it list)) - -(defmacro --map-indexed (form list) - "Eval FORM for each item in LIST and return the list of results. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. This is like -`--map', but additionally makes `it-index' available to FORM. - -This is the anaphoric counterpart to `-map-indexed'." - (declare (debug (form form))) - (let ((r (make-symbol "result"))) - `(let (,r) - (--each ,list - (push ,form ,r)) - (nreverse ,r)))) - -(defun -map-indexed (fn list) - "Apply FN to each index and item in LIST and return the list of results. -This is like `-map', but FN takes two arguments: the index of the -current element within LIST, and the element itself. - -This function's anaphoric counterpart is `--map-indexed'. - -For a side-effecting variant, see also `-each-indexed'." - (declare (important-return-value t)) - (--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) - "Use PRED to conditionally apply REP to each item in LIST. -Return a copy of LIST where the items for which PRED returns nil -are unchanged, and the rest are mapped through the REP function. - -Alias: `-replace-where' - -See also: `-update-at'" - (declare (important-return-value t)) - (--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) - "Use PRED to determine the first item in LIST to call REP on. -Return a copy of LIST where the first item for which PRED returns -non-nil is replaced with the result of calling REP on that item. - -See also: `-map-when', `-replace-first'" - (declare (important-return-value t)) - (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'." - (declare (debug (def-form def-form form))) - `(-map-first (lambda (it) (ignore it) ,pred) - (lambda (it) (ignore it) ,rep) - ,list)) - -(defun -map-last (pred rep list) - "Use PRED to determine the last item in LIST to call REP on. -Return a copy of LIST where the last item for which PRED returns -non-nil is replaced with the result of calling REP on that item. - -See also: `-map-when', `-replace-last'" - (declare (important-return-value t)) - (nreverse (-map-first pred rep (reverse list)))) - -(defmacro --map-last (pred rep list) - "Anaphoric form of `-map-last'." - (declare (debug (def-form def-form form))) - `(-map-last (lambda (it) (ignore 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." - (declare (important-return-value t)) - (--mapcat (funcall fn it) list)) - -(defmacro --iterate (form init n) - "Anaphoric version of `-iterate'." - (declare (debug (form form form))) - (let ((res (make-symbol "result")) - (len (make-symbol "n"))) - `(let ((,len ,n)) - (when (> ,len 0) - (let* ((it ,init) - (,res (list it))) - (dotimes (_ (1- ,len)) - (push (setq it ,form) ,res)) - (nreverse ,res)))))) - -(defun -iterate (fun init n) - "Return a list of iterated applications of FUN to INIT. - -This means a list of the form: - - (INIT (FUN INIT) (FUN (FUN INIT)) ...) - -N is the length of the returned list." - (declare (important-return-value t)) - (--iterate (funcall fun it) init n)) - -(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))) - -(defun -flatten-n (num list) - "Flatten NUM levels of a nested LIST. - -See also: `-flatten'" - (declare (pure t) (side-effect-free t)) - (dotimes (_ num) - (setq list (apply #'append (mapcar #'-list list)))) - list) - -(defalias '-concat #'append - "Concatenate all the arguments and make the result a list. -The result is a list whose elements are the elements of all the arguments. -Each argument may be a list, vector or string. - -All arguments except the last argument are copied. The last argument -is just used as the tail of the new list. - -\(fn &rest SEQUENCES)") - -(defalias '-copy #'copy-sequence - "Create a shallow copy of LIST. - -\(fn LIST)") - -(defmacro --splice (pred form list) - "Splice lists generated by FORM in place of items satisfying PRED in LIST. - -Evaluate PRED for each element of LIST in turn bound to `it'. -Whenever the result of PRED is nil, leave that `it' is-is. -Otherwise, evaluate FORM with the same `it' binding still in -place. The result should be a (possibly empty) list of items to -splice in place of `it' in LIST. - -This can be useful as an alternative to the `,@' construct in a -`\\=`' structure, in case you need to splice several lists at -marked positions (for example with keywords). - -This is the anaphoric counterpart to `-splice'." - (declare (debug (form form form))) - (let ((r (make-symbol "result"))) - `(let (,r) - (--each ,list - (if ,pred - (--each ,form (push it ,r)) - (push it ,r))) - (nreverse ,r)))) - -(defun -splice (pred fun list) - "Splice lists generated by FUN in place of items satisfying PRED in LIST. - -Call PRED on each element of LIST. Whenever the result of PRED -is nil, leave that `it' as-is. Otherwise, call FUN on the same -`it' that satisfied PRED. The result should be a (possibly -empty) list of items to splice in place of `it' in LIST. - -This can be useful as an alternative to the `,@' construct in a -`\\=`' structure, in case you need to splice several lists at -marked positions (for example with keywords). - -This function's anaphoric counterpart is `--splice'. - -See also: `-splice-list', `-insert-at'." - (declare (important-return-value t)) - (--splice (funcall pred it) (funcall fun it) list)) - -(defun -splice-list (pred new-list list) - "Splice NEW-LIST in place of elements matching PRED in LIST. - -See also: `-splice', `-insert-at'" - (declare (important-return-value t)) - (-splice pred (lambda (_) new-list) list)) - -(defmacro --splice-list (pred new-list list) - "Anaphoric form of `-splice-list'." - (declare (debug (def-form form form))) - `(-splice-list (lambda (it) (ignore it) ,pred) ,new-list ,list)) - -(defun -cons* (&rest args) - "Make a new list from the elements of ARGS. -The last 2 elements of ARGS are used as the final cons of the -result, so if the final element of ARGS is not a list, the result -is a dotted list. With no ARGS, return nil." - (declare (side-effect-free t)) - (let* ((len (length args)) - (tail (nthcdr (- len 2) args)) - (last (cdr tail))) - (if (null last) - (car args) - (setcdr tail (car last)) - 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 any ELEMENTS are given, append them to the list as well." - (declare (side-effect-free t)) - (-concat list (list elem) elements)) - -(defmacro --first (form list) - "Return the first item in LIST for which FORM evals to non-nil. -Return nil if no such element is found. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-first'." - (declare (debug (form form))) - (let ((n (make-symbol "needle"))) - `(let (,n) - (--each-while ,list (or (not ,form) - (ignore (setq ,n it)))) - ,n))) - -(defun -first (pred list) - "Return the first item in LIST for which PRED returns non-nil. -Return nil if no such element is found. - -To get the first item in the list no questions asked, -use `-first-item'. - -Alias: `-find'. - -This function's anaphoric counterpart is `--first'." - (declare (important-return-value t)) - (--first (funcall pred it) list)) - -(defalias '-find #'-first) -(defalias '--find '--first) - -(defmacro --some (form list) - "Return non-nil if FORM evals to non-nil for at least one item in LIST. -If so, return the first such result of FORM. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-some'." - (declare (debug (form form))) - (let ((n (make-symbol "needle"))) - `(let (,n) - (--each-while ,list (not (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'. - -This function's anaphoric counterpart is `--some'." - (declare (important-return-value t)) - (--some (funcall pred it) list)) - -(defalias '-any '-some) -(defalias '--any '--some) - -(defmacro --every (form list) - "Return non-nil if FORM evals to non-nil for all items in LIST. -If so, return the last such result of FORM. Otherwise, once an -item is reached for which FORM yields nil, return nil without -evaluating FORM for any further LIST elements. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. - -This macro is like `--every-p', but on success returns the last -non-nil result of FORM instead of just t. - -This is the anaphoric counterpart to `-every'." - (declare (debug (form form))) - (let ((a (make-symbol "all"))) - `(let ((,a t)) - (--each-while ,list (setq ,a ,form)) - ,a))) - -(defun -every (pred list) - "Return non-nil if PRED returns non-nil for all items in LIST. -If so, return the last such result of PRED. Otherwise, once an -item is reached for which PRED returns nil, return nil without -calling PRED on any further LIST elements. - -This function is like `-every-p', but on success returns the last -non-nil result of PRED instead of just t. - -This function's anaphoric counterpart is `--every'." - (declare (important-return-value t)) - (--every (funcall pred it) list)) - -(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." - (declare (important-return-value t)) - (--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', etc. - -\(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) -(put '-first-item 'pure t) -(put '-first-item 'side-effect-free t) - -(defalias '-second-item #'cadr - "Return the second item of LIST, or nil if LIST is too short. - -See also: `-first-item', `-third-item', etc. - -\(fn LIST)") - -(put '-second-item 'pure t) -(put '-second-item 'side-effect-free t) - -(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: `-second-item', `-fourth-item', etc. - -\(fn LIST)") - -(put '-third-item 'pure t) -(put '-third-item 'side-effect-free t) - -(defalias '-fourth-item - (if (fboundp 'cadddr) - #'cadddr - (lambda (list) (cadr (cddr list)))) - "Return the fourth item of LIST, or nil if LIST is too short. - -See also: `-third-item', `-fifth-item', etc. - -\(fn LIST)") - -(put '-fourth-item 'pure t) -(put '-fourth-item 'side-effect-free t) - -(defun -fifth-item (list) - "Return the fifth item of LIST, or nil if LIST is too short. - -See also: `-fourth-item', `-last-item', etc." - (declare (pure t) (side-effect-free t)) - (car (cddr (cddr list)))) - -(defun -last-item (list) - "Return the last item of LIST, or nil on an empty list. - -See also: `-first-item', etc." - (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." - (declare (important-return-value t)) - (--count (funcall pred it) list)) - -(defun ---truthy? (obj) - "Return OBJ as a boolean value (t or nil)." - (declare (pure t) (side-effect-free error-free)) - (and obj t)) - -(defmacro --any? (form list) - "Anaphoric form of `-any?'." - (declare (debug (form form))) - `(and (--some ,form ,list) t)) - -(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'" - (declare (important-return-value t)) - (--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) - "Return t if FORM evals to non-nil for all items in LIST. -Otherwise, once an item is reached for which FORM yields nil, -return nil without evaluating FORM for any further LIST elements. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. - -The similar macro `--every' is more widely useful, since it -returns the last non-nil result of FORM instead of just t on -success. - -Alias: `--all-p', `--every-p', `--every?'. - -This is the anaphoric counterpart to `-all?'." - (declare (debug (form form))) - `(and (--every ,form ,list) t)) - -(defun -all? (pred list) - "Return t if (PRED X) is non-nil for all X in LIST, else nil. -In the latter case, stop after the first X for which (PRED X) is -nil, without calling PRED on any subsequent elements of LIST. - -The similar function `-every' is more widely useful, since it -returns the last non-nil result of PRED instead of just t on -success. - -Alias: `-all-p', `-every-p', `-every?'. - -This function's anaphoric counterpart is `--all?'." - (declare (important-return-value t)) - (--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'" - (declare (important-return-value t)) - (--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 different LIST items both satisfy and do not satisfy PRED. -That is, if PRED returns both nil for at least one item, and -non-nil for at least one other item in LIST. Return nil if all -items satisfy the predicate or none of them do. - -Alias: `-only-some-p'" - (declare (important-return-value t)) - (--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 (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))) - -(defmacro --take-while (form list) - "Take successive items from LIST for which FORM evals to non-nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. Return a new -list of the successive elements from the start of LIST for which -FORM evaluates to non-nil. -This is the anaphoric counterpart to `-take-while'." - (declare (debug (form form))) - (let ((r (make-symbol "result"))) - `(let (,r) - (--each-while ,list ,form (push it ,r)) - (nreverse ,r)))) - -(defun -take-while (pred list) - "Take successive items from LIST for which PRED returns non-nil. -PRED is a function of one argument. Return a new list of the -successive elements from the start of LIST for which PRED returns -non-nil. - -This function's anaphoric counterpart is `--take-while'. - -For another variant, see also `-drop-while'." - (declare (important-return-value t)) - (--take-while (funcall pred it) list)) - -(defmacro --drop-while (form list) - "Drop successive items from LIST for which FORM evals to non-nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. Return the -tail (not a copy) of LIST starting from its first element for -which FORM evaluates to nil. -This is the anaphoric counterpart to `-drop-while'." - (declare (debug (form form))) - (let ((l (make-symbol "list"))) - `(let ((,l ,list)) - (--each-while ,l ,form (pop ,l)) - ,l))) - -(defun -drop-while (pred list) - "Drop successive items from LIST for which PRED returns non-nil. -PRED is a function of one argument. Return the tail (not a copy) -of LIST starting from its first element for which PRED returns -nil. - -This function's anaphoric counterpart is `--drop-while'. - -For another variant, see also `-take-while'." - (declare (important-return-value t)) - (--drop-while (funcall pred it) list)) - -(defun -take (n list) - "Return a copy of the first N items in LIST. -Return a copy of LIST if it contains N items or fewer. -Return nil if N is zero or less. - -See also: `-take-last'." - (declare (side-effect-free t)) - (--take-while (< it-index n) list)) - -(defun -take-last (n list) - "Return a copy of the last N items of LIST in order. -Return a copy of LIST if it contains N items or fewer. -Return nil if N is zero or less. - -See also: `-take'." - (declare (side-effect-free t)) - (copy-sequence (last list n))) - -(defalias '-drop #'nthcdr - "Return the tail (not a copy) of LIST without the first N items. -Return nil if LIST contains N items or fewer. -Return LIST if N is zero or less. - -For another variant, see also `-drop-last'. -\n(fn N LIST)") - -(defun -drop-last (n list) - "Return a copy of LIST without its last N items. -Return a copy of LIST if N is zero or less. -Return nil if LIST contains N items or fewer. - -See also: `-drop'." - (declare (side-effect-free t)) - (nbutlast (copy-sequence list) n)) - -(defun -split-at (n list) - "Split LIST into two sublists after the Nth element. -The result is a list of two elements (TAKE DROP) where TAKE is a -new list of the first N elements of LIST, and DROP is the -remaining elements of LIST (not a copy). TAKE and DROP are like -the results of `-take' and `-drop', respectively, but the split -is done in a single list traversal." - (declare (side-effect-free t)) - (let (result) - (--each-while list (< it-index n) - (push (pop list) result)) - (list (nreverse result) list))) - -(defun -rotate (n list) - "Rotate LIST N places to the right (left if N is negative). -The time complexity is O(n)." - (declare (pure t) (side-effect-free t)) - (cond ((null list) ()) - ((zerop n) (copy-sequence list)) - ((let* ((len (length list)) - (n-mod-len (mod n len)) - (new-tail-len (- len n-mod-len))) - (append (nthcdr 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) - "Use FUNC to update the Nth element of LIST. -Return a copy of LIST where the Nth element is replaced with the -result of calling FUNC on it. - -See also: `-map-when'" - (declare (important-return-value t)) - (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 def-form form))) - `(-update-at ,n (lambda (it) (ignore it) ,form) ,list)) - -(defun -remove-at (n list) - "Return LIST with its element at index N removed. -That is, remove any element selected as (nth N LIST) from LIST -and return the result. - -This is a non-destructive operation: parts of LIST (but not -necessarily all of it) are copied as needed to avoid -destructively modifying it. - -See also: `-remove-at-indices', `-remove'." - (declare (pure t) (side-effect-free t)) - (if (zerop n) - (cdr list) - (--remove-first (= it-index n) list))) - -(defun -remove-at-indices (indices list) - "Return LIST with its elements at INDICES removed. -That is, for each index I in INDICES, remove any element selected -as (nth I LIST) from LIST. - -This is a non-destructive operation: parts of LIST (but not -necessarily all of it) are copied as needed to avoid -destructively modifying it. - -See also: `-remove-at', `-remove'." - (declare (pure t) (side-effect-free t)) - (setq indices (--drop-while (< it 0) (-sort #'< indices))) - (let ((i (pop indices)) res) - (--each-while list i - (pop list) - (if (/= it-index i) - (push it res) - (while (and indices (= (car indices) i)) - (pop indices)) - (setq i (pop indices)))) - (nconc (nreverse res) list))) - -(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) - "Split LIST into a prefix satisfying PRED, and the rest. -The first sublist is the prefix of LIST with successive elements -satisfying PRED, and the second sublist is the remaining elements -that do not. The result is like performing - - ((-take-while PRED LIST) (-drop-while PRED LIST)) - -but in no more than a single pass through LIST." - (declare (important-return-value t)) - (--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 (def-form form))) - `(-split-when (lambda (it) (equal it ,item)) ,list)) - -(defmacro --split-when (form list) - "Anaphoric version of `-split-when'." - (declare (debug (def-form form))) - `(-split-when (lambda (it) (ignore 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'." - (declare (important-return-value t)) - (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) - "Split LIST into two sublists based on whether items satisfy PRED. -The result is like performing - - ((-filter PRED LIST) (-remove PRED LIST)) - -but in a single pass through LIST." - (declare (important-return-value t)) - (--separate (funcall pred it) list)) - -(defun dash--partition-all-in-steps-reversed (n step list) - "Like `-partition-all-in-steps', but the result is reversed." - (when (< step 1) - (signal 'wrong-type-argument - `("Step size < 1 results in juicy infinite loops" ,step))) - (let (result) - (while list - (push (-take n list) result) - (setq list (nthcdr step list))) - result)) - -(defun -partition-all-in-steps (n step list) - "Partition LIST into sublists of length N that are STEP items apart. -Adjacent groups may overlap if N exceeds the STEP stride. -Trailing groups may contain less than N items." - (declare (pure t) (side-effect-free t)) - (nreverse (dash--partition-all-in-steps-reversed n step list))) - -(defun -partition-in-steps (n step list) - "Partition LIST into sublists of length N that are STEP items apart. -Like `-partition-all-in-steps', but 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 (dash--partition-all-in-steps-reversed n step list))) - (while (and result (< (length (car result)) n)) - (pop 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." - (declare (important-return-value t)) - (--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)." - (declare (important-return-value t)) - (--partition-by-header (funcall fn it) list)) - -(defmacro --partition-after-pred (form list) - "Partition LIST after each element for which FORM evaluates to non-nil. -Each element of LIST in turn is bound to `it' before evaluating -FORM. - -This is the anaphoric counterpart to `-partition-after-pred'." - (let ((l (make-symbol "list")) - (r (make-symbol "result")) - (s (make-symbol "sublist"))) - `(let ((,l ,list) ,r ,s) - (when ,l - (--each ,l - (push it ,s) - (when ,form - (push (nreverse ,s) ,r) - (setq ,s ()))) - (when ,s - (push (nreverse ,s) ,r)) - (nreverse ,r))))) - -(defun -partition-after-pred (pred list) - "Partition LIST after each element for which PRED returns non-nil. - -This function's anaphoric counterpart is `--partition-after-pred'." - (declare (important-return-value t)) - (--partition-after-pred (funcall pred it) list)) - -(defun -partition-before-pred (pred list) - "Partition directly before each time PRED is true on an element of LIST." - (declare (important-return-value t)) - (nreverse (-map #'reverse - (-partition-after-pred pred (reverse list))))) - -(defun -partition-after-item (item list) - "Partition directly after each time ITEM appears in LIST." - (declare (pure t) (side-effect-free t)) - (-partition-after-pred (lambda (ele) (equal ele item)) - list)) - -(defun -partition-before-item (item list) - "Partition directly before each time ITEM appears in LIST." - (declare (pure t) (side-effect-free t)) - (-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'." - (declare (important-return-value t)) - (--group-by (funcall fn it) list)) - -(defun -interpose (sep list) - "Return a new list of all elements in LIST separated by SEP." - (declare (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 (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) - "Zip LIST1 and LIST2 into a new list according to FORM. -That is, evaluate FORM for each item pair from the two lists, and -return the list of results. The result is as long as the shorter -list. - -Each element of LIST1 and each element of LIST2 in turn are bound -pairwise to `it' and `other', respectively, and their index -within the list to `it-index', before evaluating FORM. - -This is the anaphoric counterpart to `-zip-with'." - (declare (debug (form form form))) - (let ((r (make-symbol "result")) - (l2 (make-symbol "list2"))) - `(let ((,l2 ,list2) ,r) - (--each-while ,list1 ,l2 - (let ((other (pop ,l2))) - (ignore other) - (push ,form ,r))) - (nreverse ,r)))) - -(defun -zip-with (fn list1 list2) - "Zip LIST1 and LIST2 into a new list using the function FN. -That is, apply FN pairwise taking as first argument the next -element of LIST1 and as second argument the next element of LIST2 -at the corresponding position. The result is as long as the -shorter list. - -This function's anaphoric counterpart is `--zip-with'. - -For other zips, see also `-zip-lists' and `-zip-fill'." - (declare (important-return-value t)) - (--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 element of -each list, and so on. The number of returned groupings is equal -to the length of the shortest input list, and the length of each -grouping is equal to the number of input LISTS. - -The return value is always a list of proper lists, in contrast to -`-zip' which returns a list of dotted pairs when only two input -LISTS are provided. - -See also: `-zip-pair'." - (declare (pure t) (side-effect-free t)) - (when lists - (let (results) - (while (--every it lists) - (push (mapcar #'car lists) results) - (setq lists (mapcar #'cdr lists))) - (nreverse results)))) - -(defun -zip-lists-fill (fill-value &rest lists) - "Zip LISTS together, padding shorter lists with FILL-VALUE. -This is like `-zip-lists' (which see), except it retains all -elements at positions beyond the end of the shortest list. The -number of returned groupings is equal to the length of the -longest input list, and the length of each grouping is equal to -the number of input LISTS." - (declare (pure t) (side-effect-free t)) - (when lists - (let (results) - (while (--some it lists) - (push (--map (if it (car it) fill-value) lists) results) - (setq lists (mapcar #'cdr lists))) - (nreverse results)))) - -(defun -unzip-lists (lists) - "Unzip LISTS. - -This works just like `-zip-lists' (which see), but takes a list -of lists instead of a variable number of arguments, such that - - (-unzip-lists (-zip-lists ARGS...)) - -is identity (given that the lists comprising ARGS are of the same -length)." - (declare (pure t) (side-effect-free t)) - (apply #'-zip-lists lists)) - -(defalias 'dash--length= - (if (fboundp 'length=) - #'length= - (lambda (list length) - (cond ((< length 0) nil) - ((zerop length) (null list)) - ((let ((last (nthcdr (1- length) list))) - (and last (null (cdr last)))))))) - "Return non-nil if LIST is of LENGTH. -This is a compatibility shim for `length=' in Emacs 28. -\n(fn LIST LENGTH)") - -(defun dash--zip-lists-or-pair (_form &rest lists) - "Return a form equivalent to applying `-zip' to LISTS. -This `compiler-macro' warns about discouraged `-zip' usage and -delegates to `-zip-lists' or `-zip-pair' depending on the number -of LISTS." - (if (not (dash--length= lists 2)) - (cons #'-zip-lists lists) - (let ((pair (cons #'-zip-pair lists)) - (msg "Use -zip-pair instead of -zip to get a list of pairs")) - (if (fboundp 'macroexp-warn-and-return) - (macroexp-warn-and-return msg pair) - (message msg) - pair)))) - -(defun -zip (&rest lists) - "Zip LISTS together. - -Group the head of each list, followed by the second element of -each list, and so on. The number of returned groupings is equal -to the length of the shortest input list, and the number of items -in each grouping is equal to the number of input LISTS. - -If only two LISTS are provided as arguments, return the groupings -as a list of dotted pairs. Otherwise, return the groupings as a -list of proper lists. - -Since the return value changes form depending on the number of -arguments, it is generally recommended to use `-zip-lists' -instead, or `-zip-pair' if a list of dotted pairs is desired. - -See also: `-unzip'." - (declare (compiler-macro dash--zip-lists-or-pair) - (pure t) (side-effect-free t)) - ;; For backward compatibility, return a list of dotted pairs if two - ;; arguments were provided. - (apply (if (dash--length= lists 2) #'-zip-pair #'-zip-lists) lists)) - -(defun -zip-pair (&rest lists) - "Zip LIST1 and LIST2 together. - -Make a pair with the head of each list, followed by a pair with -the second element of each list, and so on. The number of pairs -returned is equal to the length of the shorter input list. - -See also: `-zip-lists'." - (declare (advertised-calling-convention (list1 list2) "2.20.0") - (pure t) (side-effect-free t)) - (if (dash--length= lists 2) - (--zip-with (cons it other) (car lists) (cadr lists)) - (apply #'-zip-lists lists))) - -(defun -zip-fill (fill-value &rest lists) - "Zip LISTS together, padding shorter lists with FILL-VALUE. -This is like `-zip' (which see), except it retains all elements -at positions beyond the end of the shortest list. The number of -returned groupings is equal to the length of the longest input -list, and the length of each grouping is equal to the number of -input LISTS. - -Since the return value changes form depending on the number of -arguments, it is generally recommended to use `-zip-lists-fill' -instead, unless a list of dotted pairs is explicitly desired." - (declare (pure t) (side-effect-free t)) - (cond ((null lists) ()) - ((dash--length= lists 2) - (let ((list1 (car lists)) - (list2 (cadr lists)) - results) - (while (or list1 list2) - (push (cons (if list1 (pop list1) fill-value) - (if list2 (pop list2) fill-value)) - results)) - (nreverse results))) - ((apply #'-zip-lists-fill fill-value lists)))) - -(defun -unzip (lists) - "Unzip LISTS. - -This works just like `-zip' (which see), 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 of the same length, and -that `-zip' is not called with two arguments, because of the -caveat described in its docstring). - -Note in particular that calling `-unzip' on a list of two lists -will return a list of dotted pairs. - -Since the return value changes form depending on the number of -LISTS, it is generally recommended to use `-unzip-lists' instead." - (declare (pure t) (side-effect-free t)) - (apply #'-zip lists)) - -(defun -cycle (list) - "Return an infinite circular copy of LIST. -The returned list cycles through the elements of LIST and repeats -from the beginning." - (declare (pure t) (side-effect-free t)) - ;; Also works with sequences that aren't lists. - (let ((newlist (append list ()))) - (nconc newlist newlist))) - -(defun -pad (fill-value &rest lists) - "Pad each of LISTS with FILL-VALUE until they all have equal lengths. - -Ensure all LISTS are as long as the longest one by repeatedly -appending FILL-VALUE to the shorter lists, and return the -resulting LISTS." - (declare (pure t) (side-effect-free t)) - (let* ((lens (mapcar #'length lists)) - (maxlen (apply #'max 0 lens))) - (--map (append it (make-list (- maxlen (pop lens)) fill-value)) lists))) - -(defmacro --annotate (form list) - "Pair each item in LIST with the result of evaluating FORM. - -Return an alist of (RESULT . ITEM), where each ITEM is the -corresponding element of LIST, and RESULT is the value obtained -by evaluating FORM with ITEM bound to `it'. - -This is the anaphoric counterpart to `-annotate'." - (declare (debug (form form))) - `(--map (cons ,form it) ,list)) - -(defun -annotate (fn list) - "Pair each item in LIST with the result of passing it to FN. - -Return an alist of (RESULT . ITEM), where each ITEM is the -corresponding element of LIST, and RESULT is the value obtained -by calling FN on ITEM. - -This function's anaphoric counterpart is `--annotate'." - (declare (important-return-value t)) - (--annotate (funcall fn it) 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'" - (declare (important-return-value t)) - (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'" - (declare (important-return-value t)) - (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))) - -(defmacro --find-index (form list) - "Return the first index in LIST for which FORM evals to non-nil. -Return nil if no such index is found. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-find-index'." - (declare (debug (form form))) - `(--some (and ,form it-index) ,list)) - -(defun -find-index (pred list) - "Return the index of the first item satisfying PRED in LIST. -Return nil if no such item is found. - -PRED is called with one argument, the current list element, until -it returns non-nil, at which point the search terminates. - -This function's anaphoric counterpart is `--find-index'. - -See also: `-first', `-find-last-index'." - (declare (important-return-value t)) - (--find-index (funcall pred it) list)) - -(defun -elem-index (elem list) - "Return the first index of ELEM in LIST. -That is, the index within LIST of the first element that is -`equal' to ELEM. Return nil if there is no such element. - -See also: `-find-index'." - (declare (pure t) (side-effect-free t)) - (--find-index (equal elem it) list)) - -(defmacro --find-indices (form list) - "Return the list of indices in LIST for which FORM evals to non-nil. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-find-indices'." - (declare (debug (form form))) - `(--keep (and ,form it-index) ,list)) - -(defun -find-indices (pred list) - "Return the list of indices in LIST satisfying PRED. - -Each element of LIST in turn is passed to PRED. If the result is -non-nil, the index of that element in LIST is included in the -result. The returned indices are in ascending order, i.e., in -the same order as they appear in LIST. - -This function's anaphoric counterpart is `--find-indices'. - -See also: `-find-index', `-elem-indices'." - (declare (important-return-value t)) - (--find-indices (funcall pred it) list)) - -(defun -elem-indices (elem list) - "Return the list of indices at which ELEM appears in LIST. -That is, the indices of all elements of LIST `equal' to ELEM, in -the same ascending order as they appear in LIST." - (declare (pure t) (side-effect-free t)) - (--find-indices (equal elem it) list)) - -(defmacro --find-last-index (form list) - "Return the last index in LIST for which FORM evals to non-nil. -Return nil if no such index is found. -Each element of LIST in turn is bound to `it' and its index -within LIST to `it-index' before evaluating FORM. -This is the anaphoric counterpart to `-find-last-index'." - (declare (debug (form form))) - (let ((i (make-symbol "index"))) - `(let (,i) - (--each ,list - (when ,form (setq ,i it-index))) - ,i))) - -(defun -find-last-index (pred list) - "Return the index of the last item satisfying PRED in LIST. -Return nil if no such item is found. - -Predicate PRED is called with one argument each time, namely the -current list element. - -This function's anaphoric counterpart is `--find-last-index'. - -See also: `-last', `-find-index'." - (declare (important-return-value t)) - (--find-last-index (funcall pred it) 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--> (expr &rest forms) - "Thread EXPR through FORMS via `-->', while the result is non-nil. -When EXPR evaluates to non-nil, thread the result through the -first of FORMS, and when that result is non-nil, thread it -through the next form, etc." - (declare (debug (form &rest &or symbolp consp)) (indent 1)) - (if (null forms) expr - (let ((result (make-symbol "result"))) - `(-some--> (-when-let (,result ,expr) - (--> ,result ,(car forms))) - ,@(cdr forms))))) - -(defmacro -doto (init &rest forms) - "Evaluate INIT and pass it as argument to FORMS with `->'. -The RESULT of evaluating INIT is threaded through each of FORMS -individually using `->', which see. The return value is RESULT, -which FORMS may have modified by side effect." - (declare (debug (form &rest &or symbolp consp)) (indent 1)) - (let ((retval (make-symbol "result"))) - `(let ((,retval ,init)) - ,@(mapcar (lambda (form) `(-> ,retval ,form)) forms) - ,retval))) - -(defmacro --doto (init &rest forms) - "Anaphoric form of `-doto'. -This just evaluates INIT, binds the result to `it', evaluates -FORMS, and returns the final value of `it'. -Note: `it' need not be used in each form." - (declare (debug (form body)) (indent 1)) - `(let ((it ,init)) - ,@forms - it)) - -(defun -grade-up (comparator list) - "Grade elements of LIST using COMPARATOR relation. -This yields a permutation vector such that applying this -permutation to LIST sorts it in ascending order." - (declare (important-return-value t)) - (->> (--map-indexed (cons it it-index) list) - (-sort (lambda (it other) (funcall comparator (car it) (car other)))) - (mapcar #'cdr))) - -(defun -grade-down (comparator list) - "Grade elements of LIST using COMPARATOR relation. -This yields a permutation vector such that applying this -permutation to LIST sorts it in descending order." - (declare (important-return-value t)) - (->> (--map-indexed (cons it it-index) list) - (-sort (lambda (it other) (funcall comparator (car other) (car it)))) - (mapcar #'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--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)) - `(substring ,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 (-zip-fill 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 - ((and (symbolp match-form) - ;; Don't bind things like &keys as if they were vars (#395). - (not (functionp (dash--get-expand-function 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 (substring 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 (--zip-with (list (car it) (car other)) - 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 a description of the destructuring mechanism." - (declare (doc-string 2) (indent defun) - (debug (&define sexp - [&optional stringp] - [&optional ("interactive" interactive)] - def-body))) - (cond - ((nlistp match-form) - (signal 'wrong-type-argument (list #'listp match-form))) - ;; No destructuring, so just return regular `lambda' for speed. - ((-all? #'symbolp match-form) - `(lambda ,match-form ,@body)) - ((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 create the extra bindings to ensure that. - ;; We should find a way to optimize that. Not critical however. - `(lambda ,(mapcar #'cadr 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) - (signal 'wrong-number-of-arguments (list '-setq (1+ (length forms))))) - (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))) - -;; TODO: Get rid of this dynamic variable, passing it as an argument -;; instead? -(defvar -compare-fn nil - "Tests for equality use this function, or `equal' if this is nil. - -As a dynamic variable, this should be temporarily bound around -the relevant operation, rather than permanently modified. For -example: - - (let ((-compare-fn #\\='=)) - (-union \\='(1 2 3) \\='(2 3 4)))") - -(defun dash--member-fn () - "Return the flavor of `member' that goes best with `-compare-fn'." - (declare (side-effect-free error-free)) - (let ((cmp -compare-fn)) - (cond ((memq cmp '(nil equal)) #'member) - ((eq cmp #'eq) #'memq) - ((eq cmp #'eql) #'memql) - ((lambda (elt list) - (while (and list (not (funcall cmp elt (car list)))) - (pop list)) - list))))) - -(defun dash--assoc-fn () - "Return the flavor of `assoc' that goes best with `-compare-fn'." - (declare (side-effect-free error-free)) - (let ((cmp -compare-fn)) - (cond ((memq cmp '(nil equal)) #'assoc) - ((eq cmp #'eq) #'assq) - ;; Since Emacs 26, `assoc' accepts a custom `testfn'. - ;; Version testing would be simpler here, but feature - ;; testing gets more brownie points, I guess. - ((condition-case nil - (with-no-warnings (assoc nil () #'eql)) - (wrong-number-of-arguments t)) - (lambda (key alist) - (--first (and (consp it) (funcall cmp (car it) key)) alist))) - ((with-no-warnings - (lambda (key alist) - (assoc key alist cmp))))))) - -(defun dash--hash-test-fn () - "Return the hash table test function corresponding to `-compare-fn'. -Return nil if `-compare-fn' is not a known test function." - (declare (side-effect-free error-free)) - ;; In theory this could also recognize values that are custom - ;; `hash-table-test's, but too often the :test name is different - ;; from the equality function, so it doesn't seem worthwhile. - (car (memq (or -compare-fn #'equal) '(equal eq eql)))) - -(defvar dash--short-list-length 32 - "Maximum list length considered short, for optimizations. -For example, the speedup afforded by hash table lookup may start -to outweigh its runtime and memory overhead for problem sizes -greater than this value. See also the discussion in PR #305.") - -(defun -distinct (list) - "Return a copy of LIST with all duplicate elements removed. - -The test for equality is done with `equal', or with `-compare-fn' -if that is non-nil. - -Alias: `-uniq'." - (declare (important-return-value t)) - (let (test len) - (cond ((null list) ()) - ;; Use a hash table if `-compare-fn' is a known hash table - ;; test function and the list is long enough. - ((and (setq test (dash--hash-test-fn)) - (> (setq len (length list)) dash--short-list-length)) - (let ((ht (make-hash-table :test test :size len))) - (--filter (unless (gethash it ht) (puthash it t ht)) list))) - ((let ((member (dash--member-fn)) uniq) - (--each list (unless (funcall member it uniq) (push it uniq))) - (nreverse uniq)))))) - -(defalias '-uniq #'-distinct) - -(defun dash--size+ (size1 size2) - "Return the sum of nonnegative fixnums SIZE1 and SIZE2. -Return `most-positive-fixnum' on overflow. This ensures the -result is a valid size, particularly for allocating hash tables, -even in the presence of bignum support." - (declare (side-effect-free t)) - (if (< size1 (- most-positive-fixnum size2)) - (+ size1 size2) - most-positive-fixnum)) - -(defun -union (list1 list2) - "Return a new list of distinct elements appearing in either LIST1 or LIST2. - -The test for equality is done with `equal', or with `-compare-fn' -if that is non-nil." - (declare (important-return-value t)) - (let ((lists (list list1 list2)) test len union) - (cond ((null (or list1 list2))) - ;; Use a hash table if `-compare-fn' is a known hash table - ;; test function and the lists are long enough. - ((and (setq test (dash--hash-test-fn)) - (> (setq len (dash--size+ (length list1) (length list2))) - dash--short-list-length)) - (let ((ht (make-hash-table :test test :size len))) - (dolist (l lists) - (--each l (unless (gethash it ht) - (puthash it t ht) - (push it union)))))) - ((let ((member (dash--member-fn))) - (dolist (l lists) - (--each l (unless (funcall member it union) (push it union))))))) - (nreverse union))) - -(defun -intersection (list1 list2) - "Return a new list of distinct elements appearing in both LIST1 and LIST2. - -The test for equality is done with `equal', or with `-compare-fn' -if that is non-nil." - (declare (important-return-value t)) - (let (test len) - (cond ((null (and list1 list2)) ()) - ;; Use a hash table if `-compare-fn' is a known hash table - ;; test function and either list is long enough. - ((and (setq test (dash--hash-test-fn)) - (> (setq len (length list2)) dash--short-list-length)) - (let ((ht (make-hash-table :test test :size len))) - (--each list2 (puthash it t ht)) - ;; Remove visited elements to avoid duplicates. - (--filter (when (gethash it ht) (remhash it ht) t) list1))) - ((let ((member (dash--member-fn)) intersection) - (--each list1 (and (funcall member it list2) - (not (funcall member it intersection)) - (push it intersection))) - (nreverse intersection)))))) - -(defun -difference (list1 list2) - "Return a new list with the distinct members of LIST1 that are not in LIST2. - -The test for equality is done with `equal', or with `-compare-fn' -if that is non-nil." - (declare (important-return-value t)) - (let (test len1 len2) - (cond ((null list1) ()) - ((null list2) (-distinct list1)) - ;; Use a hash table if `-compare-fn' is a known hash table - ;; test function and the subtrahend is long enough. - ((and (setq test (dash--hash-test-fn)) - (setq len1 (length list1)) - (setq len2 (length list2)) - (> (max len1 len2) dash--short-list-length)) - (let ((ht1 (make-hash-table :test test :size len1)) - (ht2 (make-hash-table :test test :size len2))) - (--each list2 (puthash it t ht2)) - ;; Avoid duplicates by tracking visited items in `ht1'. - (--filter (unless (or (gethash it ht2) (gethash it ht1)) - (puthash it t ht1)) - list1))) - ((let ((member (dash--member-fn)) difference) - (--each list1 - (unless (or (funcall member it list2) - (funcall member it difference)) - (push it difference))) - (nreverse difference)))))) - -(defun -powerset (list) - "Return the power set of LIST." - (declare (pure t) (side-effect-free t)) - (if (null list) (list ()) - (let ((last (-powerset (cdr list)))) - (nconc (mapcar (lambda (x) (cons (car list) x)) last) - last)))) - -(defun -frequencies (list) - "Count the occurrences of each distinct element of LIST. - -Return an alist of (ELEMENT . N), where each ELEMENT occurs N -times in LIST. - -The test for equality is done with `equal', or with `-compare-fn' -if that is non-nil. - -See also `-count' and `-group-by'." - (declare (important-return-value t)) - (let (test len freqs) - (cond ((null list)) - ((and (setq test (dash--hash-test-fn)) - (> (setq len (length list)) dash--short-list-length)) - (let ((ht (make-hash-table :test test :size len))) - ;; Share structure between hash table and returned list. - ;; This affords a single pass that preserves the input - ;; order, conses less garbage, and is faster than a - ;; second traversal (e.g., with `maphash'). - (--each list - (let ((freq (gethash it ht))) - (if freq - (setcdr freq (1+ (cdr freq))) - (push (puthash it (cons it 1) ht) freqs)))))) - ((let ((assoc (dash--assoc-fn))) - (--each list - (let ((freq (funcall assoc it freqs))) - (if freq - (setcdr freq (1+ (cdr freq))) - (push (cons it 1) freqs))))))) - (nreverse freqs))) - -(defun dash--numbers<= (nums) - "Return non-nil if NUMS is a list of non-decreasing numbers." - (declare (pure t) (side-effect-free t)) - (or (null nums) - (let ((prev (pop nums))) - (and (numberp prev) - (--every (and (numberp it) (<= prev (setq prev it))) nums))))) - -(defun dash--next-lex-perm (array n) - "Update ARRAY of N numbers with its next lexicographic permutation. -Return nil if there is no such successor. N should be nonzero. - -This implements the salient steps of Algorithm L (Lexicographic -permutation generation) as described in DE Knuth's The Art of -Computer Programming, Volume 4A / Combinatorial Algorithms, -Part I, Addison-Wesley, 2011, § 7.2.1.2, p. 319." - (setq n (1- n)) - (let* ((l n) - (j (1- n)) - (al (aref array n)) - (aj al)) - ;; L2. [Find j]. - ;; Decrement j until a[j] < a[j+1]. - (while (and (<= 0 j) - (<= aj (setq aj (aref array j)))) - (setq j (1- j))) - ;; Terminate algorithm if j not found. - (when (>= j 0) - ;; L3. [Increase a[j]]. - ;; Decrement l until a[j] < a[l]. - (while (>= aj al) - (setq l (1- l) al (aref array l))) - ;; Swap a[j] and a[l]. - (aset array j al) - (aset array l aj) - ;; L4. [Reverse a[j+1]...a[n]]. - (setq l n) - (while (< (setq j (1+ j)) l) - (setq aj (aref array j)) - (aset array j (aref array l)) - (aset array l aj) - (setq l (1- l))) - array))) - -(defun dash--lex-perms (vec &optional original) - "Return a list of permutations of VEC in lexicographic order. -Specifically, return only the successors of VEC in lexicographic -order. Each returned permutation is a list. VEC should comprise -one or more numbers, and may be destructively modified. - -If ORIGINAL is a vector, then VEC is interpreted as a set of -indices into ORIGINAL. In this case, the indices are permuted, -and the resulting index permutations are used to dereference -elements of ORIGINAL." - (let ((len (length vec)) perms) - (while vec - (push (if original - (--map (aref original it) vec) - (append vec ())) - perms) - (setq vec (dash--next-lex-perm vec len))) - (nreverse perms))) - -(defun dash--uniq-perms (list) - "Return a list of permutations of LIST. -LIST is treated as if all its elements are distinct." - (let* ((vec (vconcat list)) - (idxs (copy-sequence vec))) - ;; Just construct a vector of the list's indices and permute that. - (dotimes (i (length idxs)) - (aset idxs i i)) - (dash--lex-perms idxs vec))) - -(defun dash--multi-perms (list freqs) - "Return a list of permutations of the multiset LIST. -FREQS should be an alist describing the frequency of each element -in LIST, as returned by `-frequencies'." - (let (;; Distinct items in `list', aka the cars of `freqs'. - (uniq (make-vector (length freqs) nil)) - ;; Indices into `uniq'. - (idxs (make-vector (length list) nil)) - ;; Current index into `idxs'. - (i 0)) - (--each freqs - (aset uniq it-index (car it)) - ;; Populate `idxs' with as many copies of each `it-index' as - ;; there are corresponding duplicates. - (dotimes (_ (cdr it)) - (aset idxs i it-index) - (setq i (1+ i)))) - (dash--lex-perms idxs uniq))) - -(defun -permutations (list) - "Return the distinct permutations of LIST. - -Duplicate elements of LIST are determined by `equal', or by -`-compare-fn' if that is non-nil." - (declare (important-return-value t)) - (cond ((null list) (list ())) - ;; Optimization: a traversal of `list' is faster than the - ;; round trip via `dash--uniq-perms' or `dash--multi-perms'. - ((dash--numbers<= list) - (dash--lex-perms (vconcat list))) - ((let ((freqs (-frequencies list))) - ;; Is each element distinct? - (unless (--every (= (cdr it) 1) freqs) - (dash--multi-perms list freqs)))) - ((dash--uniq-perms list)))) - -(defun -inits (list) - "Return all prefixes of LIST." - (declare (pure t) (side-effect-free t)) - (let ((res (list list))) - (setq list (reverse list)) - (while list - (push (reverse (!cdr list)) res)) - res)) - -(defun -tails (list) - "Return all suffixes of LIST." - (declare (pure t) (side-effect-free t)) - (-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." - (declare (pure t) (side-effect-free t)) - (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 is non-nil. As with `member', the return value is -actually the tail of LIST whose car is ELEMENT. - -Alias: `-contains-p'." - (declare (important-return-value t)) - (funcall (dash--member-fn) element list)) - -(defalias '-contains-p #'-contains?) - -(defun -same-items? (list1 list2) - "Return non-nil if LIST1 and LIST2 have the same distinct elements. - -The order of the elements in the lists does not matter. The -lists may be of different lengths, i.e., contain duplicate -elements. The test for equality is done with `equal', or with -`-compare-fn' if that is non-nil. - -Alias: `-same-items-p'." - (declare (important-return-value t)) - (let (test len1 len2) - (cond ((null (or list1 list2))) - ((null (and list1 list2)) nil) - ;; Use a hash table if `-compare-fn' is a known hash table - ;; test function and either list is long enough. - ((and (setq test (dash--hash-test-fn)) - (setq len1 (length list1)) - (setq len2 (length list2)) - (> (max len1 len2) dash--short-list-length)) - (let ((ht1 (make-hash-table :test test :size len1)) - (ht2 (make-hash-table :test test :size len2))) - (--each list1 (puthash it t ht1)) - ;; Move visited elements from `ht1' to `ht2'. This way, - ;; if visiting all of `list2' leaves `ht1' empty, then - ;; all elements from both lists have been accounted for. - (and (--every (cond ((gethash it ht1) - (remhash it ht1) - (puthash it t ht2)) - ((gethash it ht2))) - list2) - (zerop (hash-table-count ht1))))) - ((let ((member (dash--member-fn))) - (and (--all? (funcall member it list2) list1) - (--all? (funcall member it list1) list2))))))) - -(defalias '-same-items-p #'-same-items?) - -(defun -is-prefix? (prefix list) - "Return non-nil if PREFIX is a prefix of LIST. - -Alias: `-is-prefix-p'." - (declare (pure t) (side-effect-free t)) - (--each-while list (and (equal (car prefix) it) - (!cdr prefix))) - (null prefix)) - -(defun -is-suffix? (suffix list) - "Return non-nil if SUFFIX is a suffix of LIST. - -Alias: `-is-suffix-p'." - (declare (pure t) (side-effect-free t)) - (equal suffix (last list (length suffix)))) - -(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." - (declare (important-return-value t)) - (sort (copy-sequence list) comparator)) - -(defmacro --sort (form list) - "Anaphoric form of `-sort'." - (declare (debug (def-form form))) - `(-sort (lambda (it other) (ignore it other) ,form) ,list)) - -(defun -list (&optional arg &rest args) - "Ensure ARG is a list. -If ARG is already a list, return it as is (not a copy). -Otherwise, return a new list with ARG as its only element. - -Another supported calling convention is (-list &rest ARGS). -In this case, if ARG is not a list, a new list with all of -ARGS as elements is returned. This use is supported for -backward compatibility and is otherwise deprecated." - (declare (advertised-calling-convention (arg) "2.18.0") - (pure t) (side-effect-free error-free)) - (if (listp arg) arg (cons arg args))) - -(defun -repeat (n x) - "Return a new list of length N with each element being X. -Return nil if N is less than 1." - (declare (side-effect-free t)) - (and (>= n 0) (make-list n x))) - -(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)) - (or list (signal 'wrong-type-argument (list #'consp list))) - (-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)) - (or list (signal 'wrong-type-argument (list #'consp list))) - (-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." - (declare (important-return-value t)) - (--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." - (declare (important-return-value t)) - (--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 (def-form form))) - `(-max-by (lambda (it other) (ignore 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 (def-form form))) - `(-min-by (lambda (it other) (ignore it other) ,form) ,list)) - -(defun -iota (count &optional start step) - "Return a list containing COUNT numbers. -Starts from START and adds STEP each time. The default START is -zero, the default STEP is 1. -This function takes its name from the corresponding primitive in -the APL language." - (declare (side-effect-free t)) - (unless (natnump count) - (signal 'wrong-type-argument (list #'natnump count))) - (or start (setq start 0)) - (or step (setq step 1)) - (if (zerop step) - (make-list count start) - (--iterate (+ it step) start count))) - -(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'." - (declare (important-return-value t)) - (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'." - (declare (debug (def-form form))) - `(-fix (lambda (it) (ignore 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." - (declare (important-return-value t)) - (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 (def-form form))) - `(-unfold (lambda (it) (ignore it) ,form) ,seed)) - -(defun -cons-pair? (obj) - "Return non-nil if OBJ is a true cons pair. -That is, a cons (A . B) where B is not a list. - -Alias: `-cons-pair-p'." - (declare (pure t) (side-effect-free error-free)) - (nlistp (cdr-safe obj))) - -(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)) - (if (-cons-pair? val) (-cons-to-list val) (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." - (declare (important-return-value t)) - (cond - ((null tree) ()) - ((-cons-pair? tree) (funcall fn tree)) - ((consp tree) - (-reduce-r-from - folder init-value - (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree))) - ((funcall fn tree)))) - -(defmacro --tree-mapreduce-from (form folder init-value tree) - "Anaphoric form of `-tree-mapreduce-from'." - (declare (debug (def-form def-form form form))) - `(-tree-mapreduce-from (lambda (it) (ignore it) ,form) - (lambda (it acc) (ignore 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." - (declare (important-return-value t)) - (cond - ((null tree) ()) - ((-cons-pair? tree) (funcall fn tree)) - ((consp tree) - (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree))) - ((funcall fn tree)))) - -(defmacro --tree-mapreduce (form folder tree) - "Anaphoric form of `-tree-mapreduce'." - (declare (debug (def-form def-form form))) - `(-tree-mapreduce (lambda (it) (ignore it) ,form) - (lambda (it acc) (ignore it acc) ,folder) - ,tree)) - -(defun -tree-map (fn tree) - "Apply FN to each element of TREE while preserving the tree structure." - (declare (important-return-value t)) - (cond - ((null tree) ()) - ((-cons-pair? tree) (funcall fn tree)) - ((consp tree) - (mapcar (lambda (x) (-tree-map fn x)) tree)) - ((funcall fn tree)))) - -(defmacro --tree-map (form tree) - "Anaphoric form of `-tree-map'." - (declare (debug (def-form form))) - `(-tree-map (lambda (it) (ignore 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." - (declare (important-return-value t)) - (cond - ((null tree) ()) - ((-cons-pair? tree) tree) - ((consp tree) - (-reduce-r-from - fn init-value - (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree))) - (tree))) - -(defmacro --tree-reduce-from (form init-value tree) - "Anaphoric form of `-tree-reduce-from'." - (declare (debug (def-form form form))) - `(-tree-reduce-from (lambda (it acc) (ignore 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." - (declare (important-return-value t)) - (cond - ((null tree) ()) - ((-cons-pair? tree) tree) - ((consp tree) - (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree))) - (tree))) - -(defmacro --tree-reduce (form tree) - "Anaphoric form of `-tree-reduce'." - (declare (debug (def-form form))) - `(-tree-reduce (lambda (it acc) (ignore 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." - (cond ((funcall pred tree) (funcall fun tree)) - ((and (listp tree) (listp (cdr 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'." - (declare (debug (def-form def-form form))) - `(-tree-map-nodes (lambda (it) (ignore it) ,pred) - (lambda (it) (ignore 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." - (declare (important-return-value t)) - (cons tree - (and (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'." - (declare (debug (def-form def-form form))) - `(-tree-seq (lambda (it) (ignore it) ,branch) - (lambda (it) (ignore 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 (side-effect-free t)) - (-tree-map #'identity list)) - -;;; Combinators - -(defalias '-partial #'apply-partially) - -(defun -rpartial (fn &rest args) - "Return a function that is a partial application of FN to ARGS. -ARGS is a list of the last N arguments to pass to FN. The result -is a new function which does the same as FN, except that the last -N arguments are fixed at the values with which this function was -called. This is like `-partial', except the arguments are fixed -starting from the right rather than the left." - (declare (pure t) (side-effect-free error-free)) - (lambda (&rest args-before) (apply fn (append args-before args)))) - -(defun -juxt (&rest fns) - "Return a function that is the juxtaposition of FNS. -The returned function takes a variable number of ARGS, applies -each of FNS in turn to ARGS, and returns the list of results." - (declare (pure t) (side-effect-free error-free)) - (lambda (&rest args) (mapcar (lambda (x) (apply x args)) fns))) - -(defun -compose (&rest fns) - "Compose FNS into a single composite function. -Return a function that takes a variable number of ARGS, applies -the last function in FNS to ARGS, and returns the result of -calling each remaining function on the result of the previous -function, right-to-left. If no FNS are given, return a variadic -`identity' function." - (declare (pure t) (side-effect-free error-free)) - (let* ((fns (nreverse fns)) - (head (car fns)) - (tail (cdr fns))) - (cond (tail - (lambda (&rest args) - (--reduce-from (funcall it acc) (apply head args) tail))) - (fns head) - ((lambda (&optional arg &rest _) arg))))) - -(defun -applify (fn) - "Return a function that applies FN to a single list of args. -This changes the arity of FN from taking N distinct arguments to -taking 1 argument which is a list of N arguments." - (declare (pure t) (side-effect-free error-free)) - (lambda (args) (apply fn args))) - -(defun -on (op trans) - "Return a function that calls TRANS on each arg and OP on the results. -The returned function takes a variable number of arguments, calls -the function TRANS on each one in turn, and then passes those -results as the list of arguments to OP, in the same order. - -For example, the following pairs of expressions are morally -equivalent: - - (funcall (-on #\\='+ #\\='1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3)) - (funcall (-on #\\='+ #\\='1+)) = (+)" - (declare (pure t) (side-effect-free error-free)) - (lambda (&rest args) - ;; This unrolling seems to be a relatively cheap way to keep the - ;; overhead of `mapcar' + `apply' in check. - (cond ((cddr args) - (apply op (mapcar trans args))) - ((cdr args) - (funcall op (funcall trans (car args)) (funcall trans (cadr args)))) - (args - (funcall op (funcall trans (car args)))) - ((funcall op))))) - -(defun -flip (fn) - "Return a function that calls FN with its arguments reversed. -The returned function takes the same number of arguments as FN. - -For example, the following two expressions are morally -equivalent: - - (funcall (-flip #\\='-) 1 2) = (- 2 1) - -See also: `-rotate-args'." - (declare (pure t) (side-effect-free error-free)) - (lambda (&rest args) ;; Open-code for speed. - (cond ((cddr args) (apply fn (nreverse args))) - ((cdr args) (funcall fn (cadr args) (car args))) - (args (funcall fn (car args))) - ((funcall fn))))) - -(defun -rotate-args (n fn) - "Return a function that calls FN with args rotated N places to the right. -The returned function takes the same number of arguments as FN, -rotates the list of arguments N places to the right (left if N is -negative) just like `-rotate', and applies FN to the result. - -See also: `-flip'." - (declare (pure t) (side-effect-free t)) - (if (zerop n) - fn - (let ((even (= (% n 2) 0))) - (lambda (&rest args) - (cond ((cddr args) ;; Open-code for speed. - (apply fn (-rotate n args))) - ((cdr args) - (let ((fst (car args)) - (snd (cadr args))) - (funcall fn (if even fst snd) (if even snd fst)))) - (args - (funcall fn (car args))) - ((funcall fn))))))) - -(defun -const (c) - "Return a function that returns C ignoring any additional arguments. - -In types: a -> b -> a" - (declare (pure t) (side-effect-free error-free)) - (lambda (&rest _) c)) - -(defmacro -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." - (declare (debug (&optional sexp &rest &or "<>" form))) - (let* ((i 0) - (args (--keep (when (eq it '<>) - (setq i (1+ i)) - (make-symbol (format "D%d" i))) - params))) - `(lambda ,args - ,(let ((body (--map (if (eq it '<>) (pop args) it) params))) - (if (eq (car params) '<>) - (cons #'funcall body) - body))))) - -(defun -not (pred) - "Return a predicate that negates the result of PRED. -The returned predicate passes its arguments to PRED. If PRED -returns nil, the result is non-nil; otherwise the result is nil. - -See also: `-andfn' and `-orfn'." - (declare (pure t) (side-effect-free error-free)) - (lambda (&rest args) (not (apply pred args)))) - -(defun -orfn (&rest preds) - "Return a predicate that returns the first non-nil result of PREDS. -The returned predicate takes a variable number of arguments, -passes them to each predicate in PREDS in turn until one of them -returns non-nil, and returns that non-nil result without calling -the remaining PREDS. If all PREDS return nil, or if no PREDS are -given, the returned predicate returns nil. - -See also: `-andfn' and `-not'." - (declare (pure t) (side-effect-free error-free)) - ;; Open-code for speed. - (cond ((cdr preds) (lambda (&rest args) (--some (apply it args) preds))) - (preds (car preds)) - (#'ignore))) - -(defun -andfn (&rest preds) - "Return a predicate that returns non-nil if all PREDS do so. -The returned predicate P takes a variable number of arguments and -passes them to each predicate in PREDS in turn. If any one of -PREDS returns nil, P also returns nil without calling the -remaining PREDS. If all PREDS return non-nil, P returns the last -such value. If no PREDS are given, P always returns non-nil. - -See also: `-orfn' and `-not'." - (declare (pure t) (side-effect-free error-free)) - ;; Open-code for speed. - (cond ((cdr preds) (lambda (&rest args) (--every (apply it args) preds))) - (preds (car preds)) - ;; As a `pure' function, this runtime check may generate - ;; backward-incompatible bytecode for `(-andfn)' at compile-time, - ;; but I doubt that's a problem in practice (famous last words). - ((fboundp 'always) #'always) - ((lambda (&rest _) t)))) - -(defun -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' 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)))." - (declare (pure t) (side-effect-free error-free)) - (lambda (x) (--dotimes n (setq x (funcall fn x))) x)) - -(defun -counter (&optional beg end inc) - "Return a closure that counts from BEG to END, with increment INC. - -The closure will return the next value in the counting sequence -each time it is called, and nil after END is reached. BEG -defaults to 0, INC defaults to 1, and if END is nil, the counter -will increment indefinitely. - -The closure accepts any number of arguments, which are discarded." - (declare (pure t) (side-effect-free error-free)) - (let ((inc (or inc 1)) - (n (or beg 0))) - (lambda (&rest _) - (when (or (not end) (< n end)) - (prog1 n - (setq n (+ n inc))))))) - -(defvar -fixfn-max-iterations 1000 - "The default maximum number of iterations performed by `-fixfn' - unless otherwise specified.") - -(defun -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." - (declare (important-return-value t)) - (let ((eqfn (or equal-test 'equal)) - (haltfn (or halt-test - (-not - (-counter 0 -fixfn-max-iterations))))) - (lambda (x) - (let ((re (funcall fn x)) - (halt? (funcall haltfn x))) - (while (and (not halt?) (not (funcall eqfn x re))) - (setq x re - re (funcall fn re) - halt? (funcall haltfn re))) - (if halt? (cons 'halted halt?) - re))))) - -(defun -prodfn (&rest fns) - "Return a function that applies each of FNS to each of a list of arguments. - -Takes a list of N functions and returns a function that takes a -list of length N, applying Ith function to Ith 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))" - (declare (pure t) (side-effect-free t)) - (lambda (x) (--zip-with (funcall it other) fns x))) - -;;; Font lock - -(defvar dash--keywords - `(;; TODO: Do not fontify the following automatic variables - ;; globally; detect and limit to their local anaphoric scope. - (,(rx symbol-start (| "acc" "it" "it-index" "other") symbol-end) - 0 font-lock-variable-name-face) - ;; Macros in dev/examples.el. Based on `lisp-mode-symbol-regexp'. - (,(rx ?\( (group (| "defexamples" "def-example-group")) symbol-end - (+ (in "\t ")) - (group (* (| (syntax word) (syntax symbol) (: ?\\ nonl))))) - (1 font-lock-keyword-face) - (2 font-lock-function-name-face)) - ;; Symbols in dev/examples.el. - ,(rx symbol-start (| "=>" "~>" "!!>") symbol-end) - ;; Elisp macro fontification was static prior to Emacs 25. - ,@(when (< emacs-major-version 25) - (let ((macs '("!cdr" - "!cons" - "-->" - "--all-p" - "--all?" - "--annotate" - "--any" - "--any-p" - "--any?" - "--count" - "--dotimes" - "--doto" - "--drop-while" - "--each" - "--each-indexed" - "--each-r" - "--each-r-while" - "--each-while" - "--every" - "--every-p" - "--every?" - "--filter" - "--find" - "--find-index" - "--find-indices" - "--find-last-index" - "--first" - "--fix" - "--group-by" - "--if-let" - "--iterate" - "--keep" - "--last" - "--map" - "--map-first" - "--map-indexed" - "--map-last" - "--map-when" - "--mapcat" - "--max-by" - "--min-by" - "--none-p" - "--none?" - "--only-some-p" - "--only-some?" - "--partition-after-pred" - "--partition-by" - "--partition-by-header" - "--reduce" - "--reduce-from" - "--reduce-r" - "--reduce-r-from" - "--reductions" - "--reductions-from" - "--reductions-r" - "--reductions-r-from" - "--reject" - "--reject-first" - "--reject-last" - "--remove" - "--remove-first" - "--remove-last" - "--replace-where" - "--select" - "--separate" - "--some" - "--some-p" - "--some?" - "--sort" - "--splice" - "--splice-list" - "--split-when" - "--split-with" - "--take-while" - "--tree-map" - "--tree-map-nodes" - "--tree-mapreduce" - "--tree-mapreduce-from" - "--tree-reduce" - "--tree-reduce-from" - "--tree-seq" - "--unfold" - "--update-at" - "--when-let" - "--zip-with" - "->" - "->>" - "-as->" - "-cut" - "-doto" - "-if-let" - "-if-let*" - "-lambda" - "-let" - "-let*" - "-setq" - "-some-->" - "-some->" - "-some->>" - "-split-on" - "-when-let" - "-when-let*"))) - `((,(concat "(" (regexp-opt macs 'symbols)) . 1))))) - "Font lock keywords for `dash-fontify-mode'.") - -(defcustom dash-fontify-mode-lighter nil - "Mode line lighter for `dash-fontify-mode'. -Either a string to display in the mode line when -`dash-fontify-mode' is on, or nil to display -nothing (the default)." - :package-version '(dash . "2.18.0") - :type '(choice (string :tag "Lighter" :value " Dash") - (const :tag "Nothing" nil))) - -;;;###autoload -(define-minor-mode dash-fontify-mode - "Toggle fontification of Dash special variables. - -Dash-Fontify mode is a buffer-local minor mode intended for Emacs -Lisp buffers. Enabling it causes the special variables bound in -anaphoric Dash macros to be fontified. These anaphoras include -`it', `it-index', `acc', and `other'. In older Emacs versions -which do not dynamically detect macros, Dash-Fontify mode -additionally fontifies Dash macro calls. - -See also `dash-fontify-mode-lighter' and -`global-dash-fontify-mode'." - :lighter dash-fontify-mode-lighter - (if dash-fontify-mode - (font-lock-add-keywords nil dash--keywords t) - (font-lock-remove-keywords nil dash--keywords)) - (cond ((fboundp 'font-lock-flush) ;; Added in Emacs 25. - (font-lock-flush)) - ;; `font-lock-fontify-buffer' unconditionally enables - ;; `font-lock-mode' and is marked `interactive-only' in later - ;; Emacs versions which have `font-lock-flush', so we guard - ;; and pacify as needed, respectively. - (font-lock-mode - (with-no-warnings - (font-lock-fontify-buffer))))) - -(defun dash--turn-on-fontify-mode () - "Enable `dash-fontify-mode' if in an Emacs Lisp buffer." - (when (derived-mode-p #'emacs-lisp-mode) - (dash-fontify-mode))) - -;;;###autoload -(define-globalized-minor-mode global-dash-fontify-mode - dash-fontify-mode dash--turn-on-fontify-mode) - -(defcustom dash-enable-fontlock nil - "If non-nil, fontify Dash macro calls and special variables." - :set (lambda (sym val) - (set-default sym val) - (global-dash-fontify-mode (if val 1 0))) - :type 'boolean) - -(make-obsolete-variable - 'dash-enable-fontlock #'global-dash-fontify-mode "2.18.0") - -(define-obsolete-function-alias - 'dash-enable-font-lock #'global-dash-fontify-mode "2.18.0") - -;;; Info - -(defvar dash--info-doc-spec '("(dash) Index" nil "^ -+ .*: " "\\( \\|$\\)") - "The Dash :doc-spec entry for `info-lookup-alist'. -It is based on that for `emacs-lisp-mode'.") - -(defun dash--info-elisp-docs () - "Return the `emacs-lisp-mode' symbol docs from `info-lookup-alist'. -Specifically, return the cons containing their -`info-lookup->doc-spec' so that we can modify it." - (defvar info-lookup-alist) - (nthcdr 3 (assq #'emacs-lisp-mode (cdr (assq 'symbol info-lookup-alist))))) - -;;;###autoload -(defun dash-register-info-lookup () - "Register the Dash Info manual with `info-lookup-symbol'. -This allows Dash symbols to be looked up with \\[info-lookup-symbol]." - (interactive) - (require 'info-look) - (let ((docs (dash--info-elisp-docs))) - (setcar docs (append (car docs) (list dash--info-doc-spec))) - (info-lookup-reset))) - -(defun dash-unload-function () - "Remove Dash from `info-lookup-alist'. -Used by `unload-feature', which see." - (let ((docs (and (featurep 'info-look) - (dash--info-elisp-docs)))) - (when (member dash--info-doc-spec (car docs)) - (setcar docs (remove dash--info-doc-spec (car docs))) - (info-lookup-reset))) - nil) - -(provide 'dash) -;;; dash.el ends here diff --git a/elpa/dash-20230714.723/dash.info b/elpa/dash-20230714.723/dash.info deleted file mode 100644 index a99d3237..00000000 --- a/elpa/dash-20230714.723/dash.info +++ /dev/null @@ -1,4948 +0,0 @@ -This is dash.info, produced by makeinfo version 6.7 from dash.texi. - -This manual is for Dash version 2.19.1. - - Copyright © 2012–2023 Free Software Foundation, Inc. - - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU Free Documentation License, - Version 1.3 or any later version published by the Free Software - Foundation; with the Invariant Sections being “GNU General Public - License,” and no Front-Cover Texts or Back-Cover Texts. A copy of - the license is included in the section entitled “GNU Free - Documentation License”. -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 version 2.19.1. - - Copyright © 2012–2023 Free Software Foundation, Inc. - - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU Free Documentation License, - Version 1.3 or any later version published by the Free Software - Foundation; with the Invariant Sections being “GNU General Public - License,” and no Front-Cover Texts or Back-Cover Texts. A copy of - the license is included in the section entitled “GNU Free - Documentation License”. - -* Menu: - -* Installation:: Installing and configuring Dash. -* Functions:: Dash API reference. -* Development:: Contributing to Dash development. - -Appendices - -* FDL:: The license for this documentation. -* GPL:: Conditions for copying and changing Dash. -* Index:: Index including functions and macros. - - — The Detailed Node Listing — - -Installation - -* Using in a package:: Listing Dash as a package dependency. -* Fontification of special variables:: Font Lock of anaphoric macro variables. -* Info symbol lookup:: Looking up Dash symbols in this manual. - -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. -* Contributors:: List of contributors. - - -File: dash.info, Node: Installation, Next: Functions, Prev: Top, Up: Top - -1 Installation -************** - -Dash is available on GNU ELPA (https://elpa.gnu.org/), GNU-devel ELPA -(https://elpa.gnu.org/devel/), and MELPA (https://melpa.org/), and can -be installed with the standard command ‘package-install’ (*note -(emacs)Package Installation::). - -‘M-x package-install dash ’ - Install the Dash library. - - Alternatively, you can just dump ‘dash.el’ in your ‘load-path’ -somewhere (*note (emacs)Lisp Libraries::). - -* Menu: - -* Using in a package:: Listing Dash as a package dependency. -* Fontification of special variables:: Font Lock of anaphoric macro variables. -* Info symbol lookup:: Looking up Dash symbols in this manual. - - -File: dash.info, Node: Using in a package, Next: Fontification of special variables, Up: Installation - -1.1 Using in a package -====================== - -If you use Dash in your own package, be sure to list it as a dependency -in the library’s headers as follows (*note (elisp)Library Headers::). - - ;; Package-Requires: ((dash "2.19.1")) - - -File: dash.info, Node: Fontification of special variables, Next: Info symbol lookup, Prev: Using in a package, Up: Installation - -1.2 Fontification of special variables -====================================== - -The autoloaded minor mode ‘dash-fontify-mode’ is provided for optional -fontification of anaphoric Dash variables (‘it’, ‘acc’, etc.) in Emacs -Lisp buffers using search-based Font Lock (*note (emacs)Font Lock::). -In older Emacs versions which do not dynamically detect macros, the -minor mode also fontifies calls to Dash macros. - - To automatically enable the minor mode in all Emacs Lisp buffers, -just call its autoloaded global counterpart ‘global-dash-fontify-mode’, -either interactively or from your ‘user-init-file’: - - (global-dash-fontify-mode) - - -File: dash.info, Node: Info symbol lookup, Prev: Fontification of special variables, Up: Installation - -1.3 Info symbol lookup -====================== - -While editing Elisp files, you can use ‘C-h S’ (‘info-lookup-symbol’) to -look up Elisp symbols in the relevant Info manuals (*note (emacs)Info -Lookup::). To enable the same for Dash symbols, use the command -‘dash-register-info-lookup’. It can be called directly when needed, or -automatically from your ‘user-init-file’. For example: - - (with-eval-after-load 'info-look - (dash-register-info-lookup)) - - -File: dash.info, Node: Functions, Next: Development, Prev: Installation, Up: Top - -2 Functions -*********** - -This chapter contains reference documentation for the Dash API -(Application Programming Interface). The names of all public functions -defined in the library are prefixed with a dash character (‘-’). - - The library also provides anaphoric macro versions of functions where -that makes sense. The names of these macros are prefixed with two -dashes (‘--’) instead of one. - - For instance, while the function ‘-map’ applies a function to each -element of a list, its anaphoric counterpart ‘--map’ evaluates a form -with the local variable ‘it’ temporarily bound to the current list -element instead. - - ;; Normal version. - (-map (lambda (n) (* n n)) '(1 2 3 4)) - ⇒ (1 4 9 16) - - ;; Anaphoric version. - (--map (* it it) '(1 2 3 4)) - ⇒ (1 4 9 16) - - The normal version can, of course, also be written as in the -following example, which demonstrates the utility of both versions. - - (defun my-square (n) - "Return N multiplied by itself." - (* n n)) - - (-map #'my-square '(1 2 3 4)) - ⇒ (1 4 9 16) - -* 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 a new list. - - -- Function: -map (fn list) - Apply FN to each item in LIST and return the list of results. - - This function’s anaphoric counterpart is ‘--map’. - - (-map (lambda (num) (* num num)) '(1 2 3 4)) - ⇒ (1 4 9 16) - (-map #'1+ '(1 2 3 4)) - ⇒ (2 3 4 5) - (--map (* it it) '(1 2 3 4)) - ⇒ (1 4 9 16) - - -- Function: -map-when (pred rep list) - Use PRED to conditionally apply REP to each item in LIST. Return a - copy of LIST where the items for which PRED returns ‘nil’ are - unchanged, and the rest 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) - Use PRED to determine the first item in LIST to call REP on. - Return a copy of LIST where the first item for which PRED returns - non-‘nil’ is replaced with the result of calling REP on that 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) - Use PRED to determine the last item in LIST to call REP on. Return - a copy of LIST where the last item for which PRED returns non-‘nil’ - is replaced with the result of calling REP on that 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) - Apply FN to each index and item in LIST and return the list of - results. This is like ‘-map’ (*note -map::), but FN takes two - arguments: the index of the current element within LIST, and the - element itself. - - This function’s anaphoric counterpart is ‘--map-indexed’. - - For a side-effecting variant, 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) - (-map-indexed #'* '(1 2 3 4)) - ⇒ (0 2 6 12) - - -- Function: -annotate (fn list) - Pair each item in LIST with the result of passing it to FN. - - Return an alist of (RESULT . ITEM), where each ITEM is the - corresponding element of LIST, and RESULT is the value obtained by - calling FN on ITEM. - - This function’s anaphoric counterpart is ‘--annotate’. - - (-annotate #'1+ '(1 2 3)) - ⇒ ((2 . 1) (3 . 2) (4 . 3)) - (-annotate #'length '((f o o) (bar baz))) - ⇒ ((3 f o o) (2 bar baz)) - (--annotate (> it 1) '(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 items satisfying PRED in - LIST. - - Call PRED on each element of LIST. Whenever the result of PRED is - ‘nil’, leave that ‘it’ as-is. Otherwise, call FUN on the same ‘it’ - that satisfied PRED. The result should be a (possibly empty) list - of items to splice in place of ‘it’ in LIST. - - This can be useful as an alternative to the ‘,@’ construct in a ‘`’ - structure, in case you need to splice several lists at marked - positions (for example with keywords). - - This function’s anaphoric counterpart is ‘--splice’. - - See also: ‘-splice-list’ (*note -splice-list::), ‘-insert-at’ - (*note -insert-at::). - - (-splice #'numberp (lambda (n) (list n n)) '(a 1 b 2)) - ⇒ (a 1 1 b 2 2) - (--splice t (list it it) '(1 2 3 4)) - ⇒ (1 1 2 2 3 3 4 4) - (--splice (eq it :magic) '((magical) (code)) '((foo) :magic (bar))) - ⇒ ((foo) (magical) (code) (bar)) - - -- 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 (list) - Create a shallow copy of 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 - non-‘nil’. - - Alias: ‘-select’. - - This function’s anaphoric counterpart is ‘--filter’. - - For similar operations, see also ‘-keep’ (*note -keep::) and - ‘-remove’ (*note -remove::). - - (-filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) - ⇒ (2 4) - (-filter #'natnump '(-2 -1 0 1 2)) - ⇒ (0 1 2) - (--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’. - - This function’s anaphoric counterpart is ‘--remove’. - - For similar operations, see also ‘-keep’ (*note -keep::) and - ‘-filter’ (*note -filter::). - - (-remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) - ⇒ (1 3) - (-remove #'natnump '(-2 -1 0 1 2)) - ⇒ (-2 -1) - (--remove (= 0 (% it 2)) '(1 2 3 4)) - ⇒ (1 3) - - -- Function: -remove-first (pred list) - Remove the first item from LIST for which PRED returns non-‘nil’. - This is a non-destructive operation, but only the front of LIST - leading up to the removed item is a copy; the rest is LIST’s - original tail. If no item is removed, then the result is a - complete copy. - - Alias: ‘-reject-first’. - - This function’s anaphoric counterpart is ‘--remove-first’. - - See also ‘-map-first’ (*note -map-first::), ‘-remove-item’ (*note - -remove-item::), and ‘-remove-last’ (*note -remove-last::). - - (-remove-first #'natnump '(-2 -1 0 1 2)) - ⇒ (-2 -1 1 2) - (-remove-first #'stringp '(1 2 "first" "second")) - ⇒ (1 2 "second") - (--remove-first (> it 3) '(1 2 3 4 5 6)) - ⇒ (1 2 3 5 6) - - -- Function: -remove-last (pred list) - Remove the last item from LIST for which PRED returns non-‘nil’. - The result is a copy of LIST regardless of whether an element is - removed. - - Alias: ‘-reject-last’. - - This function’s anaphoric counterpart is ‘--remove-last’. - - See also ‘-map-last’ (*note -map-last::), ‘-remove-item’ (*note - -remove-item::), and ‘-remove-first’ (*note -remove-first::). - - (-remove-last #'natnump '(1 3 5 4 7 8 10 -11)) - ⇒ (1 3 5 4 7 8 -11) - (-remove-last #'stringp '(1 2 "last" "second")) - ⇒ (1 2 "last") - (--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) - Return a copy of LIST with all occurrences of ITEM removed. The - 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")) - ⇒ ("alice" "eve") - - -- Function: -non-nil (list) - Return a copy of LIST with all ‘nil’ items removed. - - (-non-nil '(nil 1 nil 2 nil nil 3 4 nil 5 nil)) - ⇒ (1 2 3 4 5) - (-non-nil '((nil))) - ⇒ ((nil)) - (-non-nil ()) - ⇒ () - - -- 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 copy of the first N items in LIST. Return a copy of LIST - if it contains N items or fewer. Return ‘nil’ if N is zero or - less. - - 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) - (-take 0 '(1 2 3 4 5)) - ⇒ () - - -- Function: -take-last (n list) - Return a copy of the last N items of LIST in order. Return a copy - of LIST if it contains N items or fewer. Return ‘nil’ if N is zero - or less. - - 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 (not a copy) of LIST without the first N items. - Return ‘nil’ if LIST contains N items or fewer. Return LIST if N - is zero or less. - - For another variant, see also ‘-drop-last’ (*note -drop-last::). - - (-drop 3 '(1 2 3 4 5)) - ⇒ (4 5) - (-drop 17 '(1 2 3 4 5)) - ⇒ () - (-drop 0 '(1 2 3 4 5)) - ⇒ (1 2 3 4 5) - - -- Function: -drop-last (n list) - Return a copy of LIST without its last N items. Return a copy of - LIST if N is zero or less. Return ‘nil’ if LIST contains N items - or fewer. - - See also: ‘-drop’ (*note -drop::). - - (-drop-last 3 '(1 2 3 4 5)) - ⇒ (1 2) - (-drop-last 17 '(1 2 3 4 5)) - ⇒ () - (-drop-last 0 '(1 2 3 4 5)) - ⇒ (1 2 3 4 5) - - -- Function: -take-while (pred list) - Take successive items from LIST for which PRED returns non-‘nil’. - PRED is a function of one argument. Return a new list of the - successive elements from the start of LIST for which PRED returns - non-‘nil’. - - This function’s anaphoric counterpart is ‘--take-while’. - - For another variant, see also ‘-drop-while’ (*note -drop-while::). - - (-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) - Drop successive items from LIST for which PRED returns non-‘nil’. - PRED is a function of one argument. Return the tail (not a copy) - of LIST starting from its first element for which PRED returns - ‘nil’. - - This function’s anaphoric counterpart is ‘--drop-while’. - - For another variant, see also ‘-take-while’ (*note -take-while::). - - (-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 each - item in LIST. Like ‘-filter’ (*note -filter::), but returns the - non-‘nil’ results of FN instead of the corresponding elements of - LIST. - - Its anaphoric counterpart is ‘--keep’. - - (-keep #'cdr '((1 2 3) (4 5) (6))) - ⇒ ((2 3) (5)) - (-keep (lambda (n) (and (> n 3) (* 10 n))) '(1 2 3 4 5 6)) - ⇒ (40 50 60) - (--keep (and (> it 3) (* 10 it)) '(1 2 3 4 5 6)) - ⇒ (40 50 60) - - -- Function: -concat (&rest sequences) - Concatenate all the arguments and make the result a list. The - result is a list whose elements are the elements of all the - arguments. Each argument may be a list, vector or string. - - All arguments except the last argument are copied. The last - argument is just used as the tail of the new list. - - (-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) - Use FUNC to update the Nth element of LIST. Return a copy of LIST - where the Nth element is replaced with the result of calling FUNC - on it. - - 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 LIST with its element at index N removed. That is, remove - any element selected as (nth N LIST) from LIST and return the - result. - - This is a non-destructive operation: parts of LIST (but not - necessarily all of it) are copied as needed to avoid destructively - modifying it. - - See also: ‘-remove-at-indices’ (*note -remove-at-indices::), - ‘-remove’ (*note -remove::). - - (-remove-at 0 '(a b c)) - ⇒ (b c) - (-remove-at 1 '(a b c)) - ⇒ (a c) - (-remove-at 2 '(a b c)) - ⇒ (a b) - - -- Function: -remove-at-indices (indices list) - Return LIST with its elements at INDICES removed. That is, for - each index I in INDICES, remove any element selected as (nth I - LIST) from LIST. - - This is a non-destructive operation: parts of LIST (but not - necessarily all of it) are copied as needed to avoid destructively - modifying it. - - See also: ‘-remove-at’ (*note -remove-at::), ‘-remove’ (*note - -remove::). - - (-remove-at-indices '(0) '(a b c d e)) - ⇒ (b c d e) - (-remove-at-indices '(1 3) '(a b c d e)) - ⇒ (a c e) - (-remove-at-indices '(4 0 2) '(a b c d e)) - ⇒ (b d) - - -File: dash.info, Node: Reductions, Next: Unfolding, Prev: List to list, Up: Functions - -2.4 Reductions -============== - -Functions reducing lists to a single value (which may also be a list). - - -- Function: -reduce-from (fn init list) - Reduce the function FN across LIST, starting with INIT. Return the - result of applying FN to INIT and the first element of LIST, then - applying FN to that result and the second element, etc. If LIST is - empty, return INIT without calling FN. - - This function’s anaphoric counterpart is ‘--reduce-from’. - - For other folds, see also ‘-reduce’ (*note -reduce::) and - ‘-reduce-r’ (*note -reduce-r::). - - (-reduce-from #'- 10 '(1 2 3)) - ⇒ 4 - (-reduce-from #'list 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 init list) - Reduce the function FN across LIST in reverse, starting with INIT. - Return the result of applying FN to the last element of LIST and - INIT, then applying FN to the second-to-last element and the - previous result of FN, etc. That is, the first argument of FN is - the current element, and its second argument the accumulated value. - If LIST is empty, return INIT without calling FN. - - This function is like ‘-reduce-from’ (*note -reduce-from::) but the - operation associates from the right rather than left. In other - words, it starts from the end of LIST and flips the arguments to - FN. Conceptually, it is like replacing the conses in LIST with - applications of FN, and its last link with INIT, and evaluating the - resulting expression. - - This function’s anaphoric counterpart is ‘--reduce-r-from’. - - For other folds, see also ‘-reduce-r’ (*note -reduce-r::) and - ‘-reduce’ (*note -reduce::). - - (-reduce-r-from #'- 10 '(1 2 3)) - ⇒ -8 - (-reduce-r-from #'list 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) - Reduce the function FN across LIST. Return the result of applying - FN to the first two elements of LIST, then applying FN to that - result and the third element, etc. If LIST contains a single - element, return it without calling FN. If LIST is empty, return - the result of calling FN with no arguments. - - This function’s anaphoric counterpart is ‘--reduce’. - - For other folds, see also ‘-reduce-from’ (*note -reduce-from::) and - ‘-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) - Reduce the function FN across LIST in reverse. Return the result - of applying FN to the last two elements of LIST, then applying FN - to the third-to-last element and the previous result of FN, etc. - That is, the first argument of FN is the current element, and its - second argument the accumulated value. If LIST contains a single - element, return it without calling FN. If LIST is empty, return - the result of calling FN with no arguments. - - This function is like ‘-reduce’ (*note -reduce::) but the operation - associates from the right rather than left. In other words, it - starts from the end of LIST and flips the arguments to FN. - Conceptually, it is like replacing the conses in LIST with - applications of FN, ignoring its last link, and evaluating the - resulting expression. - - This function’s anaphoric counterpart is ‘--reduce-r’. - - For other folds, see also ‘-reduce-r-from’ (*note -reduce-r-from::) - and ‘-reduce’ (*note -reduce::). - - (-reduce-r #'- '(1 2 3 4)) - ⇒ -2 - (-reduce-r #'list '(1 2 3 4)) - ⇒ (1 (2 (3 4))) - (--reduce-r (format "%s-%d" acc it) '(1 2 3)) - ⇒ "3-2-1" - - -- Function: -reductions-from (fn init list) - Return a list of FN’s intermediate reductions across LIST. That - is, a list of the intermediate values of the accumulator when - ‘-reduce-from’ (*note -reduce-from::) (which see) is called with - the same arguments. - - This function’s anaphoric counterpart is ‘--reductions-from’. - - For other folds, see also ‘-reductions’ (*note -reductions::) and - ‘-reductions-r’ (*note -reductions-r::). - - (-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) - (--reductions-from (format "(FN %s %d)" acc it) "INIT" '(1 2 3)) - ⇒ ("INIT" "(FN INIT 1)" "(FN (FN INIT 1) 2)" "(FN (FN (FN INIT 1) 2) 3)") - - -- Function: -reductions-r-from (fn init list) - Return a list of FN’s intermediate reductions across reversed LIST. - That is, a list of the intermediate values of the accumulator when - ‘-reduce-r-from’ (*note -reduce-r-from::) (which see) is called - with the same arguments. - - This function’s anaphoric counterpart is ‘--reductions-r-from’. - - For other folds, see also ‘-reductions’ (*note -reductions::) and - ‘-reductions-r’ (*note -reductions-r::). - - (-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) - (--reductions-r-from (format "(FN %d %s)" it acc) "INIT" '(1 2 3)) - ⇒ ("(FN 1 (FN 2 (FN 3 INIT)))" "(FN 2 (FN 3 INIT))" "(FN 3 INIT)" "INIT") - - -- Function: -reductions (fn list) - Return a list of FN’s intermediate reductions across LIST. That - is, a list of the intermediate values of the accumulator when - ‘-reduce’ (*note -reduce::) (which see) is called with the same - arguments. - - This function’s anaphoric counterpart is ‘--reductions’. - - For other folds, see also ‘-reductions’ (*note -reductions::) and - ‘-reductions-r’ (*note -reductions-r::). - - (-reductions #'+ '(1 2 3 4)) - ⇒ (1 3 6 10) - (-reductions #'* '(1 2 3 4)) - ⇒ (1 2 6 24) - (--reductions (format "(FN %s %d)" acc it) '(1 2 3)) - ⇒ (1 "(FN 1 2)" "(FN (FN 1 2) 3)") - - -- Function: -reductions-r (fn list) - Return a list of FN’s intermediate reductions across reversed LIST. - That is, a list of the intermediate values of the accumulator when - ‘-reduce-r’ (*note -reduce-r::) (which see) is called with the same - arguments. - - This function’s anaphoric counterpart is ‘--reductions-r’. - - For other folds, see also ‘-reductions-r-from’ (*note - -reductions-r-from::) and ‘-reductions’ (*note -reductions::). - - (-reductions-r #'+ '(1 2 3 4)) - ⇒ (10 9 7 4) - (-reductions-r #'* '(1 2 3 4)) - ⇒ (24 24 12 4) - (--reductions-r (format "(FN %d %s)" it acc) '(1 2 3)) - ⇒ ("(FN 1 (FN 2 3))" "(FN 2 3)" 3) - - -- 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→ Wrong type argument: consp, nil - - -- 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→ Wrong type argument: consp, nil - - -- 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)) - ⇒ () - (-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)) - ⇒ () - (-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) - - -- Function: -frequencies (list) - Count the occurrences of each distinct element of LIST. - - Return an alist of (ELEMENT . N), where each ELEMENT occurs N - times in LIST. - - The test for equality is done with ‘equal’, or with ‘-compare-fn’ - if that is non-‘nil’. - - See also ‘-count’ (*note -count::) and ‘-group-by’ (*note - -group-by::). - - (-frequencies ()) - ⇒ () - (-frequencies '(1 2 3 1 2 1)) - ⇒ ((1 . 3) (2 . 2) (3 . 1)) - (let ((-compare-fn #'string=)) (-frequencies '(a "a"))) - ⇒ ((a . 2)) - - -File: dash.info, Node: Unfolding, Next: Predicates, Prev: Reductions, Up: Functions - -2.5 Unfolding -============= - -Operations dual to reductions, building lists from a 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 the 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)) - - -- Function: -repeat (n x) - Return a new list of length N with each element being X. Return - ‘nil’ if N is less than 1. - - (-repeat 3 :a) - ⇒ (:a :a :a) - (-repeat 1 :a) - ⇒ (:a) - (-repeat 0 :a) - ⇒ () - - -- Function: -cycle (list) - Return an infinite circular copy of LIST. The returned list cycles - through the elements of LIST and repeats 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-lists (-cycle '(3)) '(1 2)) - ⇒ ((3 1) (3 2)) - - -File: dash.info, Node: Predicates, Next: Partitioning, Prev: Unfolding, Up: Functions - -2.6 Predicates -============== - -Reductions of one or more lists to a boolean value. - - -- Function: -some (pred list) - Return (PRED x) for the first LIST item where (PRED x) is - non-‘nil’, else ‘nil’. - - Alias: ‘-any’. - - This function’s anaphoric counterpart is ‘--some’. - - (-some #'stringp '(1 "2" 3)) - ⇒ t - (--some (string-match-p "x" it) '("foo" "axe" "xor")) - ⇒ 1 - (--some (= it-index 3) '(0 1 2)) - ⇒ nil - - -- Function: -every (pred list) - Return non-‘nil’ if PRED returns non-‘nil’ for all items in LIST. - If so, return the last such result of PRED. Otherwise, once an - item is reached for which PRED returns ‘nil’, return ‘nil’ without - calling PRED on any further LIST elements. - - This function is like ‘-every-p’, but on success returns the last - non-‘nil’ result of PRED instead of just ‘t’. - - This function’s anaphoric counterpart is ‘--every’. - - (-every #'numberp '(1 2 3)) - ⇒ t - (--every (string-match-p "x" it) '("axe" "xor")) - ⇒ 0 - (--every (= it it-index) '(0 1 3)) - ⇒ nil - - -- 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? #'numberp '(nil 0 t)) - ⇒ t - (-any? #'numberp '(nil t t)) - ⇒ 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’. - In the latter case, stop after the first X for which (PRED X) is - ‘nil’, without calling PRED on any subsequent elements of LIST. - - The similar function ‘-every’ (*note -every::) is more widely - useful, since it returns the last non-‘nil’ result of PRED instead - of just ‘t’ on success. - - Alias: ‘-all-p’, ‘-every-p’, ‘-every?’. - - This function’s anaphoric counterpart is ‘--all?’. - - (-all? #'numberp '(1 2 3)) - ⇒ t - (-all? #'numberp '(2 t 6)) - ⇒ nil - (--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 different LIST items both satisfy and do not satisfy - PRED. That is, if PRED returns both ‘nil’ for at least one item, - and non-‘nil’ for at least one other item in LIST. Return ‘nil’ if - all items satisfy the predicate or none of them do. - - 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 is non-‘nil’. As with ‘member’, the return value is - actually the tail of LIST whose car is ELEMENT. - - Alias: ‘-contains-p’. - - (-contains? '(1 2 3) 1) - ⇒ (1 2 3) - (-contains? '(1 2 3) 2) - ⇒ (2 3) - (-contains? '(1 2 3) 4) - ⇒ () - - -- Function: -is-prefix? (prefix list) - Return non-‘nil’ if PREFIX is a 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 a 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 - - -- Function: -cons-pair? (obj) - Return non-‘nil’ if OBJ is a true cons pair. That is, a cons (A . - B) where B is not a list. - - Alias: ‘-cons-pair-p’. - - (-cons-pair? '(1 . 2)) - ⇒ t - (-cons-pair? '(1 2)) - ⇒ nil - (-cons-pair? '(1)) - ⇒ nil - - -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) - Split LIST into two sublists after the Nth element. The result is - a list of two elements (TAKE DROP) where TAKE is a new list of the - first N elements of LIST, and DROP is the remaining elements of - LIST (not a copy). TAKE and DROP are like the results of ‘-take’ - (*note -take::) and ‘-drop’ (*note -drop::), respectively, but the - split is done in a single list traversal. - - (-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) - (-split-at 0 '(1 2 3 4 5)) - ⇒ (nil (1 2 3 4 5)) - - -- Function: -split-with (pred list) - Split LIST into a prefix satisfying PRED, and the rest. The first - sublist is the prefix of LIST with successive elements satisfying - PRED, and the second sublist is the remaining elements that do not. - The result is like performing - - ((-take-while PRED LIST) (-drop-while PRED LIST)) - - but in no more than a single pass through 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) - Split LIST into two sublists based on whether items satisfy PRED. - The result is like performing - - ((-filter PRED LIST) (-remove PRED LIST)) - - but in a single pass through 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) - Partition LIST into sublists of length N that are STEP items apart. - Like ‘-partition-all-in-steps’ (*note -partition-all-in-steps::), - but 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) - Partition LIST into sublists of length N that are STEP items apart. - Adjacent groups may overlap if N exceeds the STEP stride. Trailing - 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 LIST after each element for which PRED returns non-‘nil’. - - This function’s anaphoric counterpart is ‘--partition-after-pred’. - - (-partition-after-pred #'booleanp ()) - ⇒ () - (-partition-after-pred #'booleanp '(t t)) - ⇒ ((t) (t)) - (-partition-after-pred #'booleanp '(0 0 t t 0 t)) - ⇒ ((0 0 t) (t) (0 t)) - - -- Function: -partition-before-pred (pred list) - Partition directly before each time PRED is true on an element of - LIST. - - (-partition-before-pred #'booleanp ()) - ⇒ () - (-partition-before-pred #'booleanp '(0 t)) - ⇒ ((0) (t)) - (-partition-before-pred #'booleanp '(0 0 t 0 t t)) - ⇒ ((0 0) (t 0) (t) (t)) - - -- 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 -============ - -Functions retrieving or sorting based on list indices and related -predicates. - - -- Function: -elem-index (elem list) - Return the first index of ELEM in LIST. That is, the index within - LIST of the first element that is ‘equal’ to ELEM. Return ‘nil’ if - there is no such element. - - See also: ‘-find-index’ (*note -find-index::). - - (-elem-index 2 '(6 7 8 3 4)) - ⇒ nil - (-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 list of indices at which ELEM appears in LIST. That is, - the indices of all elements of LIST ‘equal’ to ELEM, in the same - ascending order as they appear in LIST. - - (-elem-indices 2 '(6 7 8 3 4 1)) - ⇒ () - (-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) - Return the index of the first item satisfying PRED in LIST. Return - ‘nil’ if no such item is found. - - PRED is called with one argument, the current list element, until - it returns non-‘nil’, at which point the search terminates. - - This function’s anaphoric counterpart is ‘--find-index’. - - See also: ‘-first’ (*note -first::), ‘-find-last-index’ (*note - -find-last-index::). - - (-find-index #'numberp '(a b c)) - ⇒ nil - (-find-index #'natnump '(1 0 -1)) - ⇒ 0 - (--find-index (> it 5) '(2 4 1 6 3 3 5 8)) - ⇒ 3 - - -- Function: -find-last-index (pred list) - Return the index of the last item satisfying PRED in LIST. Return - ‘nil’ if no such item is found. - - Predicate PRED is called with one argument each time, namely the - current list element. - - This function’s anaphoric counterpart is ‘--find-last-index’. - - See also: ‘-last’ (*note -last::), ‘-find-index’ (*note - -find-index::). - - (-find-last-index #'numberp '(a b c)) - ⇒ nil - (--find-last-index (> it 5) '(2 7 1 6 3 8 5 2)) - ⇒ 5 - (-find-last-index (-partial #'string< 'a) '(c b a)) - ⇒ 1 - - -- Function: -find-indices (pred list) - Return the list of indices in LIST satisfying PRED. - - Each element of LIST in turn is passed to PRED. If the result is - non-‘nil’, the index of that element in LIST is included in the - result. The returned indices are in ascending order, i.e., in the - same order as they appear in LIST. - - This function’s anaphoric counterpart is ‘--find-indices’. - - See also: ‘-find-index’ (*note -find-index::), ‘-elem-indices’ - (*note -elem-indices::). - - (-find-indices #'numberp '(a b c)) - ⇒ () - (-find-indices #'numberp '(8 1 d 2 b c a 3)) - ⇒ (0 1 3 7) - (--find-indices (> it 5) '(2 4 1 6 3 3 5 8)) - ⇒ (3 7) - - -- Function: -grade-up (comparator list) - Grade elements of LIST using COMPARATOR relation. This yields 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. This yields 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 (list1 list2) - Return a new list of distinct elements appearing in either LIST1 or - LIST2. - - The test for equality is done with ‘equal’, or with ‘-compare-fn’ - if that is non-‘nil’. - - (-union '(1 2 3) '(3 4 5)) - ⇒ (1 2 3 4 5) - (-union '(1 2 2 4) ()) - ⇒ (1 2 4) - (-union '(1 1 2 2) '(4 4 3 2 1)) - ⇒ (1 2 4 3) - - -- Function: -difference (list1 list2) - Return a new list with the distinct members of LIST1 that are not - in LIST2. - - The test for equality is done with ‘equal’, or with ‘-compare-fn’ - if that is 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 (list1 list2) - Return a new list of distinct elements appearing in both LIST1 and - LIST2. - - The test for equality is done with ‘equal’, or with ‘-compare-fn’ - if that is non-‘nil’. - - (-intersection () ()) - ⇒ () - (-intersection '(1 2 3) '(4 5 6)) - ⇒ () - (-intersection '(1 2 2 3) '(4 3 3 2)) - ⇒ (2 3) - - -- Function: -powerset (list) - Return the power set of LIST. - - (-powerset ()) - ⇒ (nil) - (-powerset '(x y)) - ⇒ ((x y) (x) (y) nil) - (-powerset '(x y z)) - ⇒ ((x y z) (x y) (x z) (x) (y z) (y) (z) nil) - - -- Function: -permutations (list) - Return the distinct permutations of LIST. - - Duplicate elements of LIST are determined by ‘equal’, or by - ‘-compare-fn’ if that is non-‘nil’. - - (-permutations ()) - ⇒ (nil) - (-permutations '(a a b)) - ⇒ ((a a b) (a b a) (b a a)) - (-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 copy of LIST with all duplicate elements removed. - - The test for equality is done with ‘equal’, or with ‘-compare-fn’ - if that is non-‘nil’. - - Alias: ‘-uniq’. - - (-distinct ()) - ⇒ () - (-distinct '(1 1 2 3 3)) - ⇒ (1 2 3) - (-distinct '(t t t)) - ⇒ (t) - - -- Function: -same-items? (list1 list2) - Return non-‘nil’ if LIST1 and LIST2 have the same distinct - elements. - - The order of the elements in the lists does not matter. The lists - may be of different lengths, i.e., contain duplicate elements. The - test for equality is done with ‘equal’, or with ‘-compare-fn’ if - that is non-‘nil’. - - Alias: ‘-same-items-p’. - - (-same-items? '(1 2 3) '(1 2 3)) - ⇒ t - (-same-items? '(1 1 2 3) '(3 3 2 1)) - ⇒ t - (-same-items? '(1 2 3) '(1 2 3 4)) - ⇒ nil - - -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 (left if N is negative). 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: -cons* (&rest args) - Make a new list from the elements of ARGS. The last 2 elements of - ARGS are used as the final cons of the result, so if the final - element of ARGS is not a list, the result is a dotted list. With - no ARGS, return ‘nil’. - - (-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 any ELEMENTS are given, append them 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: -iota (count &optional start step) - Return a list containing COUNT numbers. Starts from START and adds - STEP each time. The default START is zero, the default STEP is 1. - This function takes its name from the corresponding primitive in - the APL language. - - (-iota 6) - ⇒ (0 1 2 3 4 5) - (-iota 4 2.5 -2) - ⇒ (2.5 0.5 -1.5 -3.5) - (-iota -1) - error→ Wrong type argument: natnump, -1 - - -- Function: -zip-with (fn list1 list2) - Zip LIST1 and LIST2 into a new list using the function FN. That - is, apply FN pairwise taking as first argument the next element of - LIST1 and as second argument the next element of LIST2 at the - corresponding position. The result is as long as the shorter list. - - This function’s anaphoric counterpart is ‘--zip-with’. - - For other zips, see also ‘-zip-lists’ (*note -zip-lists::) and - ‘-zip-fill’ (*note -zip-fill::). - - (-zip-with #'+ '(1 2 3 4) '(5 6 7)) - ⇒ (6 8 10) - (-zip-with #'cons '(1 2 3) '(4 5 6 7)) - ⇒ ((1 . 4) (2 . 5) (3 . 6)) - (--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde)) - ⇒ ("Batman & Robin" "Jekyll & Hyde") - - -- Function: -zip-pair (list1 list2) - Zip LIST1 and LIST2 together. - - Make a pair with the head of each list, followed by a pair with the - second element of each list, and so on. The number of pairs - returned is equal to the length of the shorter input list. - - See also: ‘-zip-lists’ (*note -zip-lists::). - - (-zip-pair '(1 2 3 4) '(5 6 7)) - ⇒ ((1 . 5) (2 . 6) (3 . 7)) - (-zip-pair '(1 2 3) '(4 5 6)) - ⇒ ((1 . 4) (2 . 5) (3 . 6)) - (-zip-pair '(1 2) '(3)) - ⇒ ((1 . 3)) - - -- Function: -zip-lists (&rest lists) - Zip LISTS together. - - Group the head of each list, followed by the second element of each - list, and so on. The number of returned groupings is equal to the - length of the shortest input list, and the length of each grouping - is equal to the number of input LISTS. - - The return value is always a list of proper lists, in contrast to - ‘-zip’ (*note -zip::) which returns a list of dotted pairs when - only two input LISTS are provided. - - See also: ‘-zip-pair’ (*note -zip-pair::). - - (-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-lists-fill (fill-value &rest lists) - Zip LISTS together, padding shorter lists with FILL-VALUE. This is - like ‘-zip-lists’ (*note -zip-lists::) (which see), except it - retains all elements at positions beyond the end of the shortest - list. The number of returned groupings is equal to the length of - the longest input list, and the length of each grouping is equal to - the number of input LISTS. - - (-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) - ⇒ ((1 3 6) (2 4 0) (0 5 0)) - (-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) - ⇒ ((1 3 5) (2 4 6)) - (-zip-lists-fill 0 '(1 2 3) nil) - ⇒ ((1 0) (2 0) (3 0)) - - -- Function: -zip (&rest lists) - Zip LISTS together. - - Group the head of each list, followed by the second element of each - list, and so on. The number of returned groupings is equal to the - length of the shortest input list, and the number of items in each - grouping is equal to the number of input LISTS. - - If only two LISTS are provided as arguments, return the groupings - as a list of dotted pairs. Otherwise, return the groupings as a - list of proper lists. - - Since the return value changes form depending on the number of - arguments, it is generally recommended to use ‘-zip-lists’ (*note - -zip-lists::) instead, or ‘-zip-pair’ (*note -zip-pair::) if a list - of dotted pairs is desired. - - See also: ‘-unzip’ (*note -unzip::). - - (-zip '(1 2 3 4) '(5 6 7) '(8 9)) - ⇒ ((1 5 8) (2 6 9)) - (-zip '(1 2 3) '(4 5 6) '(7 8 9)) - ⇒ ((1 4 7) (2 5 8) (3 6 9)) - (-zip '(1 2 3)) - ⇒ ((1) (2) (3)) - - -- Function: -zip-fill (fill-value &rest lists) - Zip LISTS together, padding shorter lists with FILL-VALUE. This is - like ‘-zip’ (*note -zip::) (which see), except it retains all - elements at positions beyond the end of the shortest list. The - number of returned groupings is equal to the length of the longest - input list, and the length of each grouping is equal to the number - of input LISTS. - - Since the return value changes form depending on the number of - arguments, it is generally recommended to use ‘-zip-lists-fill’ - (*note -zip-lists-fill::) instead, unless a list of dotted pairs is - explicitly desired. - - (-zip-fill 0 '(1 2 3) '(4 5)) - ⇒ ((1 . 4) (2 . 5) (3 . 0)) - (-zip-fill 0 () '(1 2 3)) - ⇒ ((0 . 1) (0 . 2) (0 . 3)) - (-zip-fill 0 '(1 2) '(3 4) '(5 6)) - ⇒ ((1 3 5) (2 4 6)) - - -- Function: -unzip-lists (lists) - Unzip LISTS. - - This works just like ‘-zip-lists’ (*note -zip-lists::) (which see), - but takes a list of lists instead of a variable number of - arguments, such that - - (-unzip-lists (-zip-lists ARGS...)) - - is identity (given that the lists comprising ARGS are of the same - length). - - (-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) - ⇒ ((1 2) (3 4) (5 6)) - (-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) - ⇒ ((1 4 6 8) (2 5 7 9)) - (-unzip-lists '((1 2 3) (4 5 6))) - ⇒ ((1 4) (2 5) (3 6)) - - -- Function: -unzip (lists) - Unzip LISTS. - - This works just like ‘-zip’ (*note -zip::) (which see), 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 of the same length, and that - ‘-zip’ (*note -zip::) is not called with two arguments, because of - the caveat described in its docstring). - - Note in particular that calling ‘-unzip’ (*note -unzip::) on a list - of two lists will return a list of dotted pairs. - - Since the return value changes form depending on the number of - LISTS, it is generally recommended to use ‘-unzip-lists’ (*note - -unzip-lists::) instead. - - (-unzip (-zip '(1 2) '(3 4) '(5 6))) - ⇒ ((1 . 2) (3 . 4) (5 . 6)) - (-unzip '((1 2 3) (4 5 6))) - ⇒ ((1 . 4) (2 . 5) (3 . 6)) - (-unzip '((1 2 3) (4 5) (6 7) (8 9))) - ⇒ ((1 4 6 8) (2 5 7 9)) - - -- Function: -pad (fill-value &rest lists) - Pad each of LISTS with FILL-VALUE until they all have equal - lengths. - - Ensure all LISTS are as long as the longest one by repeatedly - appending FILL-VALUE to the shorter lists, and return the resulting - LISTS. - - (-pad 0 ()) - ⇒ (nil) - (-pad 0 '(1 2) '(3 4)) - ⇒ ((1 2) (3 4)) - (-pad 0 '(1 2) '(3 4 5 6) '(7 8 9)) - ⇒ ((1 2 0 0) (3 4 5 6) (7 8 9 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 item in LIST for which PRED returns non-‘nil’. - Return ‘nil’ if no such element is found. - - To get the first item in the list no questions asked, use - ‘-first-item’ (*note -first-item::). - - Alias: ‘-find’. - - This function’s anaphoric counterpart is ‘--first’. - - (-first #'natnump '(-1 0 1)) - ⇒ 0 - (-first #'null '(1 2 3)) - ⇒ nil - (--first (> it 2) '(1 2 3)) - ⇒ 3 - - -- 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::), etc. - - (-first-item ()) - ⇒ () - (-first-item '(1 2 3 4 5)) - ⇒ 1 - (let ((list (list 1 2 3))) (setf (-first-item list) 5) list) - ⇒ (5 2 3) - - -- Function: -second-item (list) - Return the second item of LIST, or ‘nil’ if LIST is too short. - - See also: ‘-first-item’ (*note -first-item::), ‘-third-item’ (*note - -third-item::), etc. - - (-second-item ()) - ⇒ () - (-second-item '(1 2 3 4 5)) - ⇒ 2 - (let ((list (list 1 2))) (setf (-second-item list) 5) list) - ⇒ (1 5) - - -- Function: -third-item (list) - Return the third item of LIST, or ‘nil’ if LIST is too short. - - See also: ‘-second-item’ (*note -second-item::), ‘-fourth-item’ - (*note -fourth-item::), etc. - - (-third-item ()) - ⇒ () - (-third-item '(1 2)) - ⇒ () - (-third-item '(1 2 3 4 5)) - ⇒ 3 - - -- Function: -fourth-item (list) - Return the fourth item of LIST, or ‘nil’ if LIST is too short. - - See also: ‘-third-item’ (*note -third-item::), ‘-fifth-item’ (*note - -fifth-item::), etc. - - (-fourth-item ()) - ⇒ () - (-fourth-item '(1 2 3)) - ⇒ () - (-fourth-item '(1 2 3 4 5)) - ⇒ 4 - - -- Function: -fifth-item (list) - Return the fifth item of LIST, or ‘nil’ if LIST is too short. - - See also: ‘-fourth-item’ (*note -fourth-item::), ‘-last-item’ - (*note -last-item::), etc. - - (-fifth-item ()) - ⇒ () - (-fifth-item '(1 2 3 4)) - ⇒ () - (-fifth-item '(1 2 3 4 5)) - ⇒ 5 - - -- Function: -last-item (list) - Return the last item of LIST, or ‘nil’ on an empty list. - - See also: ‘-first-item’ (*note -first-item::), etc. - - (-last-item ()) - ⇒ () - (-last-item '(1 2 3 4 5)) - ⇒ 5 - (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 (arg) - Ensure ARG is a list. If ARG is already a list, return it as is - (not a copy). Otherwise, return a new list with ARG as its only - element. - - Another supported calling convention is (-list &rest ARGS). In - this case, if ARG is not a list, a new list with all of ARGS as - elements is returned. This use is supported for backward - compatibility and is otherwise deprecated. - - (-list 1) - ⇒ (1) - (-list ()) - ⇒ () - (-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))) - ⇒ ((1) (2) (3)) - (let ((l '((starwars scifi) (jedi starwars warrior)))) (--fix (-uniq (--mapcat (cons it (cdr (assq it l))) 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) '("" ("

" "text" "

") "")) - ⇒ (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 "")))) '(body (p "some words") (div "more" (b "bold") "words"))) - ⇒ "

some words

more bold words
" - - -- 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) "}" '((elisp-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam))))) - ⇒ "{elisp-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 (list (list 1))) (b (-clone a))) (setcar (car a) 2) b) - ⇒ ((1)) - - -File: dash.info, Node: Threading macros, Next: Binding, Prev: Tree operations, Up: Functions - -2.12 Threading macros -===================== - -Macros that conditionally combine sequential forms for brevity or -readability. - - -- 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--> (expr &rest forms) - Thread EXPR through FORMS via ‘-->’ (*note -->::), while the result - is non-‘nil’. When EXPR evaluates to non-‘nil’, thread the result - through the first of FORMS, and when that result is non-‘nil’, - thread it through the next form, etc. - - (-some--> "def" (concat "abc" it "ghi")) - ⇒ "abcdefghi" - (-some--> nil (concat "abc" it "ghi")) - ⇒ nil - (-some--> '(0 1) (-remove #'natnump it) (append it it) (-map #'1+ it)) - ⇒ () - - -- Macro: -doto (init &rest forms) - Evaluate INIT and pass it as argument to FORMS with ‘->’ (*note - ->::). The RESULT of evaluating INIT is threaded through each of - FORMS individually using ‘->’ (*note ->::), which see. The return - value is RESULT, which FORMS may have modified by side effect. - - (-doto (list 1 2 3) pop pop) - ⇒ (3) - (-doto (cons 1 2) (setcar 3) (setcdr 4)) - ⇒ (3 . 4) - (gethash 'k (--doto (make-hash-table) (puthash 'k 'v it))) - ⇒ v - - -File: dash.info, Node: Binding, Next: Side effects, Prev: Threading macros, Up: Functions - -2.13 Binding -============ - -Macros that combine ‘let’ and ‘let*’ with destructuring and 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::). - - (-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::). - - (-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 a description of the 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 ([match-form val] ...) - 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. - - (let (a) (-setq a 1) a) - ⇒ 1 - (let (a b) (-setq (a b) (list 1 2)) (list a b)) - ⇒ (1 2) - (let (c) (-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 on each element of LIST. Return ‘nil’; this function is - intended for side effects. - - Its anaphoric counterpart is ‘--each’. - - For access to the current element’s index in LIST, see - ‘-each-indexed’ (*note -each-indexed::). - - (let (l) (-each '(1 2 3) (lambda (x) (push x l))) l) - ⇒ (3 2 1) - (let (l) (--each '(1 2 3) (push it l)) l) - ⇒ (3 2 1) - (-each '(1 2 3) #'identity) - ⇒ nil - - -- Function: -each-while (list pred fn) - Call FN on each ITEM in LIST, while (PRED ITEM) is non-‘nil’. Once - an ITEM is reached for which PRED returns ‘nil’, FN is no longer - called. Return ‘nil’; this function is intended for side effects. - - Its anaphoric counterpart is ‘--each-while’. - - (let (l) (-each-while '(2 4 5 6) #'even? (lambda (x) (push x l))) l) - ⇒ (4 2) - (let (l) (--each-while '(1 2 3 4) (< it 3) (push it l)) l) - ⇒ (2 1) - (let ((s 0)) (--each-while '(1 3 4 5) (< it 5) (setq s (+ s it))) s) - ⇒ 8 - - -- Function: -each-indexed (list fn) - Call FN on each index and element of LIST. For each ITEM at INDEX - in LIST, call (funcall FN INDEX ITEM). Return ‘nil’; this function - is intended for side effects. - - See also: ‘-map-indexed’ (*note -map-indexed::). - - (let (l) (-each-indexed '(a b c) (lambda (i x) (push (list x i) l))) l) - ⇒ ((c 2) (b 1) (a 0)) - (let (l) (--each-indexed '(a b c) (push (list it it-index) l)) l) - ⇒ ((c 2) (b 1) (a 0)) - (let (l) (--each-indexed () (push it l)) l) - ⇒ () - - -- Function: -each-r (list fn) - Call FN on each element of LIST in reversed order. Return ‘nil’; - this function is intended for side effects. - - Its anaphoric counterpart is ‘--each-r’. - - (let (l) (-each-r '(1 2 3) (lambda (x) (push x l))) l) - ⇒ (1 2 3) - (let (l) (--each-r '(1 2 3) (push it l)) l) - ⇒ (1 2 3) - (-each-r '(1 2 3) #'identity) - ⇒ nil - - -- Function: -each-r-while (list pred fn) - Call FN on each ITEM in reversed LIST, while (PRED ITEM) is - non-‘nil’. Once an ITEM is reached for which PRED returns ‘nil’, - FN is no longer called. Return ‘nil’; this function is intended - for side effects. - - Its anaphoric counterpart is ‘--each-r-while’. - - (let (l) (-each-r-while '(2 4 5 6) #'even? (lambda (x) (push x l))) l) - ⇒ (6) - (let (l) (--each-r-while '(1 2 3 4) (>= it 3) (push it l)) l) - ⇒ (3 4) - (let ((s 0)) (--each-r-while '(1 2 3 5) (> it 1) (setq s (+ s it))) s) - ⇒ 10 - - -- Function: -dotimes (num fn) - Call FN NUM times, presumably for side effects. FN is called with - a single argument on successive integers running from 0, inclusive, - to NUM, exclusive. FN is not called if NUM is less than 1. - - This function’s anaphoric counterpart is ‘--dotimes’. - - (let (s) (-dotimes 3 (lambda (n) (push n s))) s) - ⇒ (2 1 0) - (let (s) (-dotimes 0 (lambda (n) (push n s))) s) - ⇒ () - (let (s) (--dotimes 5 (push it s)) s) - ⇒ (4 3 2 1 0) - - -File: dash.info, Node: Destructive operations, Next: Function combinators, Prev: Side effects, Up: Functions - -2.15 Destructive operations -=========================== - -Macros that modify variables holding lists. - - -- 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 -========================= - -Functions that manipulate and compose other functions. - - -- Function: -partial (fun &rest args) - Return a function that is a partial application of FUN to ARGS. - ARGS is a list of the first N arguments to pass to FUN. The result - is a new function which does the same as FUN, except that the first - N arguments are fixed at the values with which this function was - called. - - (funcall (-partial #'+ 5)) - ⇒ 5 - (funcall (-partial #'- 5) 3) - ⇒ 2 - (funcall (-partial #'+ 5 2) 3) - ⇒ 10 - - -- Function: -rpartial (fn &rest args) - Return a function that is a partial application of FN to ARGS. - ARGS is a list of the last N arguments to pass to FN. The result - is a new function which does the same as FN, except that the last N - arguments are fixed at the values with which this function was - called. This is like ‘-partial’ (*note -partial::), except the - arguments are fixed starting from the right rather than the left. - - (funcall (-rpartial #'- 5)) - ⇒ -5 - (funcall (-rpartial #'- 5) 8) - ⇒ 3 - (funcall (-rpartial #'- 5 2) 10) - ⇒ 3 - - -- Function: -juxt (&rest fns) - Return a function that is the juxtaposition of FNS. The returned - function takes a variable number of ARGS, applies each of FNS in - turn to ARGS, and returns the list of results. - - (funcall (-juxt) 1 2) - ⇒ () - (funcall (-juxt #'+ #'- #'* #'/) 7 5) - ⇒ (12 2 35 1) - (mapcar (-juxt #'number-to-string #'1+) '(1 2)) - ⇒ (("1" 2) ("2" 3)) - - -- Function: -compose (&rest fns) - Compose FNS into a single composite function. Return a function - that takes a variable number of ARGS, applies the last function in - FNS to ARGS, and returns the result of calling each remaining - function on the result of the previous function, right-to-left. If - no FNS are given, return a variadic ‘identity’ function. - - (funcall (-compose #'- #'1+ #'+) 1 2 3) - ⇒ -7 - (funcall (-compose #'identity #'1+) 3) - ⇒ 4 - (mapcar (-compose #'not #'stringp) '(nil "")) - ⇒ (t nil) - - -- Function: -applify (fn) - Return a function that applies FN to a single list of args. This - changes the arity of FN from taking N distinct arguments to taking - 1 argument which is a list of N arguments. - - (funcall (-applify #'+) nil) - ⇒ 0 - (mapcar (-applify #'+) '((1 1 1) (1 2 3) (5 5 5))) - ⇒ (3 6 15) - (funcall (-applify #'<) '(3 6)) - ⇒ t - - -- Function: -on (op trans) - Return a function that calls TRANS on each arg and OP on the - results. The returned function takes a variable number of - arguments, calls the function TRANS on each one in turn, and then - passes those results as the list of arguments to OP, in the same - order. - - For example, the following pairs of expressions are morally - equivalent: - - (funcall (-on #’+ #’1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3)) (funcall - (-on #’+ #’1+)) = (+) - - (-sort (-on #'< #'length) '((1 2 3) (1) (1 2))) - ⇒ ((1) (1 2) (1 2 3)) - (funcall (-on #'min #'string-to-number) "22" "2" "1" "12") - ⇒ 1 - (-min-by (-on #'> #'length) '((1 2 3) (4) (1 2))) - ⇒ (4) - - -- Function: -flip (fn) - Return a function that calls FN with its arguments reversed. The - returned function takes the same number of arguments as FN. - - For example, the following two expressions are morally equivalent: - - (funcall (-flip #’-) 1 2) = (- 2 1) - - See also: ‘-rotate-args’ (*note -rotate-args::). - - (-sort (-flip #'<) '(4 3 6 1)) - ⇒ (6 4 3 1) - (funcall (-flip #'-) 3 2 1 10) - ⇒ 4 - (funcall (-flip #'1+) 1) - ⇒ 2 - - -- Function: -rotate-args (n fn) - Return a function that calls FN with args rotated N places to the - right. The returned function takes the same number of arguments as - FN, rotates the list of arguments N places to the right (left if N - is negative) just like ‘-rotate’ (*note -rotate::), and applies FN - to the result. - - See also: ‘-flip’ (*note -flip::). - - (funcall (-rotate-args -1 #'list) 1 2 3 4) - ⇒ (2 3 4 1) - (funcall (-rotate-args 1 #'-) 1 10 100) - ⇒ 89 - (funcall (-rotate-args 2 #'list) 3 4 5 1 2) - ⇒ (1 2 3 4 5) - - -- 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 - (mapcar (-const 1) '("a" "b" "c" "d")) - ⇒ (1 1 1 1) - (-sum (mapcar (-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 vector string)) - ⇒ ((1 2 3) [1 2 3] "\1\2\3") - - -- Function: -not (pred) - Return a predicate that negates the result of PRED. The returned - predicate passes its arguments to PRED. If PRED returns ‘nil’, the - result is non-‘nil’; otherwise the result is ‘nil’. - - See also: ‘-andfn’ (*note -andfn::) and ‘-orfn’ (*note -orfn::). - - (funcall (-not #'numberp) "5") - ⇒ t - (-sort (-not #'<) '(5 2 1 0 6)) - ⇒ (6 5 2 1 0) - (-filter (-not (-partial #'< 4)) '(1 2 3 4 5 6 7 8)) - ⇒ (1 2 3 4) - - -- Function: -orfn (&rest preds) - Return a predicate that returns the first non-‘nil’ result of - PREDS. The returned predicate takes a variable number of - arguments, passes them to each predicate in PREDS in turn until one - of them returns non-‘nil’, and returns that non-‘nil’ result - without calling the remaining PREDS. If all PREDS return ‘nil’, or - if no PREDS are given, the returned predicate returns ‘nil’. - - See also: ‘-andfn’ (*note -andfn::) and ‘-not’ (*note -not::). - - (-filter (-orfn #'natnump #'booleanp) '(1 nil "a" -4 b c t)) - ⇒ (1 nil t) - (funcall (-orfn #'symbolp (-cut string-match-p "x" <>)) "axe") - ⇒ 1 - (funcall (-orfn #'= #'+) 1 1) - ⇒ t - - -- Function: -andfn (&rest preds) - Return a predicate that returns non-‘nil’ if all PREDS do so. The - returned predicate P takes a variable number of arguments and - passes them to each predicate in PREDS in turn. If any one of - PREDS returns ‘nil’, P also returns ‘nil’ without calling the - remaining PREDS. If all PREDS return non-‘nil’, P returns the last - such value. If no PREDS are given, P always returns non-‘nil’. - - See also: ‘-orfn’ (*note -orfn::) and ‘-not’ (*note -not::). - - (-filter (-andfn #'numberp (-cut < <> 5)) '(a 1 b 6 c 2)) - ⇒ (1 2) - (mapcar (-andfn #'numberp #'1+) '(a 1 b 6)) - ⇒ (nil 2 nil 7) - (funcall (-andfn #'= #'+) 1 1) - ⇒ 2 - - -- 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=) 0.7) - ⇒ 0.7390851332151607 - (funcall (-fixfn (lambda (x) (expt (+ x 10) 0.25))) 2.0) - ⇒ 1.8555845286409378 - (funcall (-fixfn #'sin #'approx=) 0.1) - ⇒ (halted . t) - - -- Function: -prodfn (&rest fns) - Return a function that applies each of FNS to each of a list of - arguments. - - Takes a list of N functions and returns a function that takes a - list of length N, applying Ith function to Ith 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))) - ⇒ ((0 3) (2 5) (4 7)) - (apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) - ⇒ 6 - - -File: dash.info, Node: Development, Next: FDL, Prev: Functions, Up: Top - -3 Development -************* - -The Dash repository is hosted on GitHub at -. - -* Menu: - -* Contribute:: How to contribute. -* Contributors:: List of contributors. - - -File: dash.info, Node: Contribute, Next: Contributors, Up: Development - -3.1 Contribute -============== - -Yes, please do. Pure functions in the list manipulation realm only, -please. There’s a suite of examples/tests in ‘dev/examples.el’, so -remember to add tests for your additions, or they may get broken later. - - Run the tests with ‘make check’. Regenerate the docs with ‘make -docs’. Contributors are encouraged to install these commands as a Git -pre-commit hook, so that the tests are always running and the docs are -always in sync: - - $ cp dev/pre-commit.sh .git/hooks/pre-commit - - Oh, and don’t edit ‘README.md’ or ‘dash.texi’ directly, as they are -auto-generated. Instead, change their respective templates -‘readme-template.md’ or ‘dash-template.texi’. - - To ensure that Dash can be distributed with GNU ELPA or Emacs, we -require that all contributors assign copyright to the Free Software -Foundation. For more on this, *note (emacs)Copyright Assignment::. - - -File: dash.info, Node: Contributors, Prev: Contribute, Up: Development - -3.2 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 a variadic version of ‘-zip’. - • Fredrik Bergroth (https://github.com/fbergroth) made the ‘-if-let’ - family use ‘-let’ destructuring and improved the script for - generating documentation. - • Mark Oteiza (https://github.com/holomorph) contributed ‘-iota’ and - 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. - • Cam Saul (https://github.com/camsaul) contributed ‘-some->’, - ‘-some->>’, and ‘-some-->’. - • Basil L. Contovounesios (https://github.com/basil-conto) - contributed ‘-common-prefix’, ‘-common-suffix’, and various other - improvements. - • Paul Pogonyshev (https://github.com/doublep) contributed ‘-each-r’ - and ‘-each-r-while’. - - Thanks! - - New contributors are very welcome. *Note Contribute::. - - -File: dash.info, Node: FDL, Next: GPL, Prev: Development, Up: Top - -Appendix A GNU Free Documentation License -***************************************** - - Version 1.3, 3 November 2008 - - Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. - - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - 0. PREAMBLE - - The purpose of this License is to make a manual, textbook, or other - functional and useful document “free” in the sense of freedom: to - assure everyone the effective freedom to copy and redistribute it, - with or without modifying it, either commercially or - noncommercially. Secondarily, this License preserves for the - author and publisher a way to get credit for their work, while not - being considered responsible for modifications made by others. - - This License is a kind of “copyleft”, which means that derivative - works of the document must themselves be free in the same sense. - It complements the GNU General Public License, which is a copyleft - license designed for free software. - - We have designed this License in order to use it for manuals for - free software, because free software needs free documentation: a - free program should come with manuals providing the same freedoms - that the software does. But this License is not limited to - software manuals; it can be used for any textual work, regardless - of subject matter or whether it is published as a printed book. We - recommend this License principally for works whose purpose is - instruction or reference. - - 1. APPLICABILITY AND DEFINITIONS - - This License applies to any manual or other work, in any medium, - that contains a notice placed by the copyright holder saying it can - be distributed under the terms of this License. Such a notice - grants a world-wide, royalty-free license, unlimited in duration, - to use that work under the conditions stated herein. The - “Document”, below, refers to any such manual or work. Any member - of the public is a licensee, and is addressed as “you”. You accept - the license if you copy, modify or distribute the work in a way - requiring permission under copyright law. - - A “Modified Version” of the Document means any work containing the - Document or a portion of it, either copied verbatim, or with - modifications and/or translated into another language. - - A “Secondary Section” is a named appendix or a front-matter section - of the Document that deals exclusively with the relationship of the - publishers or authors of the Document to the Document’s overall - subject (or to related matters) and contains nothing that could - fall directly within that overall subject. (Thus, if the Document - is in part a textbook of mathematics, a Secondary Section may not - explain any mathematics.) The relationship could be a matter of - historical connection with the subject or with related matters, or - of legal, commercial, philosophical, ethical or political position - regarding them. - - The “Invariant Sections” are certain Secondary Sections whose - titles are designated, as being those of Invariant Sections, in the - notice that says that the Document is released under this License. - If a section does not fit the above definition of Secondary then it - is not allowed to be designated as Invariant. The Document may - contain zero Invariant Sections. If the Document does not identify - any Invariant Sections then there are none. - - The “Cover Texts” are certain short passages of text that are - listed, as Front-Cover Texts or Back-Cover Texts, in the notice - that says that the Document is released under this License. A - Front-Cover Text may be at most 5 words, and a Back-Cover Text may - be at most 25 words. - - A “Transparent” copy of the Document means a machine-readable copy, - represented in a format whose specification is available to the - general public, that is suitable for revising the document - straightforwardly with generic text editors or (for images composed - of pixels) generic paint programs or (for drawings) some widely - available drawing editor, and that is suitable for input to text - formatters or for automatic translation to a variety of formats - suitable for input to text formatters. A copy made in an otherwise - Transparent file format whose markup, or absence of markup, has - been arranged to thwart or discourage subsequent modification by - readers is not Transparent. An image format is not Transparent if - used for any substantial amount of text. A copy that is not - “Transparent” is called “Opaque”. - - Examples of suitable formats for Transparent copies include plain - ASCII without markup, Texinfo input format, LaTeX input format, - SGML or XML using a publicly available DTD, and standard-conforming - simple HTML, PostScript or PDF designed for human modification. - Examples of transparent image formats include PNG, XCF and JPG. - Opaque formats include proprietary formats that can be read and - edited only by proprietary word processors, SGML or XML for which - the DTD and/or processing tools are not generally available, and - the machine-generated HTML, PostScript or PDF produced by some word - processors for output purposes only. - - The “Title Page” means, for a printed book, the title page itself, - plus such following pages as are needed to hold, legibly, the - material this License requires to appear in the title page. For - works in formats which do not have any title page as such, “Title - Page” means the text near the most prominent appearance of the - work’s title, preceding the beginning of the body of the text. - - The “publisher” means any person or entity that distributes copies - of the Document to the public. - - A section “Entitled XYZ” means a named subunit of the Document - whose title either is precisely XYZ or contains XYZ in parentheses - following text that translates XYZ in another language. (Here XYZ - stands for a specific section name mentioned below, such as - “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) - To “Preserve the Title” of such a section when you modify the - Document means that it remains a section “Entitled XYZ” according - to this definition. - - The Document may include Warranty Disclaimers next to the notice - which states that this License applies to the Document. These - Warranty Disclaimers are considered to be included by reference in - this License, but only as regards disclaiming warranties: any other - implication that these Warranty Disclaimers may have is void and - has no effect on the meaning of this License. - - 2. VERBATIM COPYING - - You may copy and distribute the Document in any medium, either - commercially or noncommercially, provided that this License, the - copyright notices, and the license notice saying this License - applies to the Document are reproduced in all copies, and that you - add no other conditions whatsoever to those of this License. You - may not use technical measures to obstruct or control the reading - or further copying of the copies you make or distribute. However, - you may accept compensation in exchange for copies. If you - distribute a large enough number of copies you must also follow the - conditions in section 3. - - You may also lend copies, under the same conditions stated above, - and you may publicly display copies. - - 3. COPYING IN QUANTITY - - If you publish printed copies (or copies in media that commonly - have printed covers) of the Document, numbering more than 100, and - the Document’s license notice requires Cover Texts, you must - enclose the copies in covers that carry, clearly and legibly, all - these Cover Texts: Front-Cover Texts on the front cover, and - Back-Cover Texts on the back cover. Both covers must also clearly - and legibly identify you as the publisher of these copies. The - front cover must present the full title with all words of the title - equally prominent and visible. You may add other material on the - covers in addition. Copying with changes limited to the covers, as - long as they preserve the title of the Document and satisfy these - conditions, can be treated as verbatim copying in other respects. - - If the required texts for either cover are too voluminous to fit - legibly, you should put the first ones listed (as many as fit - reasonably) on the actual cover, and continue the rest onto - adjacent pages. - - If you publish or distribute Opaque copies of the Document - numbering more than 100, you must either include a machine-readable - Transparent copy along with each Opaque copy, or state in or with - each Opaque copy a computer-network location from which the general - network-using public has access to download using public-standard - network protocols a complete Transparent copy of the Document, free - of added material. If you use the latter option, you must take - reasonably prudent steps, when you begin distribution of Opaque - copies in quantity, to ensure that this Transparent copy will - remain thus accessible at the stated location until at least one - year after the last time you distribute an Opaque copy (directly or - through your agents or retailers) of that edition to the public. - - It is requested, but not required, that you contact the authors of - the Document well before redistributing any large number of copies, - to give them a chance to provide you with an updated version of the - Document. - - 4. MODIFICATIONS - - You may copy and distribute a Modified Version of the Document - under the conditions of sections 2 and 3 above, provided that you - release the Modified Version under precisely this License, with the - Modified Version filling the role of the Document, thus licensing - distribution and modification of the Modified Version to whoever - possesses a copy of it. In addition, you must do these things in - the Modified Version: - - A. Use in the Title Page (and on the covers, if any) a title - distinct from that of the Document, and from those of previous - versions (which should, if there were any, be listed in the - History section of the Document). You may use the same title - as a previous version if the original publisher of that - version gives permission. - - B. List on the Title Page, as authors, one or more persons or - entities responsible for authorship of the modifications in - the Modified Version, together with at least five of the - principal authors of the Document (all of its principal - authors, if it has fewer than five), unless they release you - from this requirement. - - C. State on the Title page the name of the publisher of the - Modified Version, as the publisher. - - D. Preserve all the copyright notices of the Document. - - E. Add an appropriate copyright notice for your modifications - adjacent to the other copyright notices. - - F. Include, immediately after the copyright notices, a license - notice giving the public permission to use the Modified - Version under the terms of this License, in the form shown in - the Addendum below. - - G. Preserve in that license notice the full lists of Invariant - Sections and required Cover Texts given in the Document’s - license notice. - - H. Include an unaltered copy of this License. - - I. Preserve the section Entitled “History”, Preserve its Title, - and add to it an item stating at least the title, year, new - authors, and publisher of the Modified Version as given on the - Title Page. If there is no section Entitled “History” in the - Document, create one stating the title, year, authors, and - publisher of the Document as given on its Title Page, then add - an item describing the Modified Version as stated in the - previous sentence. - - J. Preserve the network location, if any, given in the Document - for public access to a Transparent copy of the Document, and - likewise the network locations given in the Document for - previous versions it was based on. These may be placed in the - “History” section. You may omit a network location for a work - that was published at least four years before the Document - itself, or if the original publisher of the version it refers - to gives permission. - - K. For any section Entitled “Acknowledgements” or “Dedications”, - Preserve the Title of the section, and preserve in the section - all the substance and tone of each of the contributor - acknowledgements and/or dedications given therein. - - L. Preserve all the Invariant Sections of the Document, unaltered - in their text and in their titles. Section numbers or the - equivalent are not considered part of the section titles. - - M. Delete any section Entitled “Endorsements”. Such a section - may not be included in the Modified Version. - - N. Do not retitle any existing section to be Entitled - “Endorsements” or to conflict in title with any Invariant - Section. - - O. Preserve any Warranty Disclaimers. - - If the Modified Version includes new front-matter sections or - appendices that qualify as Secondary Sections and contain no - material copied from the Document, you may at your option designate - some or all of these sections as invariant. To do this, add their - titles to the list of Invariant Sections in the Modified Version’s - license notice. These titles must be distinct from any other - section titles. - - You may add a section Entitled “Endorsements”, provided it contains - nothing but endorsements of your Modified Version by various - parties—for example, statements of peer review or that the text has - been approved by an organization as the authoritative definition of - a standard. - - You may add a passage of up to five words as a Front-Cover Text, - and a passage of up to 25 words as a Back-Cover Text, to the end of - the list of Cover Texts in the Modified Version. Only one passage - of Front-Cover Text and one of Back-Cover Text may be added by (or - through arrangements made by) any one entity. If the Document - already includes a cover text for the same cover, previously added - by you or by arrangement made by the same entity you are acting on - behalf of, you may not add another; but you may replace the old - one, on explicit permission from the previous publisher that added - the old one. - - The author(s) and publisher(s) of the Document do not by this - License give permission to use their names for publicity for or to - assert or imply endorsement of any Modified Version. - - 5. COMBINING DOCUMENTS - - You may combine the Document with other documents released under - this License, under the terms defined in section 4 above for - modified versions, provided that you include in the combination all - of the Invariant Sections of all of the original documents, - unmodified, and list them all as Invariant Sections of your - combined work in its license notice, and that you preserve all - their Warranty Disclaimers. - - The combined work need only contain one copy of this License, and - multiple identical Invariant Sections may be replaced with a single - copy. If there are multiple Invariant Sections with the same name - but different contents, make the title of each such section unique - by adding at the end of it, in parentheses, the name of the - original author or publisher of that section if known, or else a - unique number. Make the same adjustment to the section titles in - the list of Invariant Sections in the license notice of the - combined work. - - In the combination, you must combine any sections Entitled - “History” in the various original documents, forming one section - Entitled “History”; likewise combine any sections Entitled - “Acknowledgements”, and any sections Entitled “Dedications”. You - must delete all sections Entitled “Endorsements.” - - 6. COLLECTIONS OF DOCUMENTS - - You may make a collection consisting of the Document and other - documents released under this License, and replace the individual - copies of this License in the various documents with a single copy - that is included in the collection, provided that you follow the - rules of this License for verbatim copying of each of the documents - in all other respects. - - You may extract a single document from such a collection, and - distribute it individually under this License, provided you insert - a copy of this License into the extracted document, and follow this - License in all other respects regarding verbatim copying of that - document. - - 7. AGGREGATION WITH INDEPENDENT WORKS - - A compilation of the Document or its derivatives with other - separate and independent documents or works, in or on a volume of a - storage or distribution medium, is called an “aggregate” if the - copyright resulting from the compilation is not used to limit the - legal rights of the compilation’s users beyond what the individual - works permit. When the Document is included in an aggregate, this - License does not apply to the other works in the aggregate which - are not themselves derivative works of the Document. - - If the Cover Text requirement of section 3 is applicable to these - copies of the Document, then if the Document is less than one half - of the entire aggregate, the Document’s Cover Texts may be placed - on covers that bracket the Document within the aggregate, or the - electronic equivalent of covers if the Document is in electronic - form. Otherwise they must appear on printed covers that bracket - the whole aggregate. - - 8. TRANSLATION - - Translation is considered a kind of modification, so you may - distribute translations of the Document under the terms of section - 4. Replacing Invariant Sections with translations requires special - permission from their copyright holders, but you may include - translations of some or all Invariant Sections in addition to the - original versions of these Invariant Sections. You may include a - translation of this License, and all the license notices in the - Document, and any Warranty Disclaimers, provided that you also - include the original English version of this License and the - original versions of those notices and disclaimers. In case of a - disagreement between the translation and the original version of - this License or a notice or disclaimer, the original version will - prevail. - - If a section in the Document is Entitled “Acknowledgements”, - “Dedications”, or “History”, the requirement (section 4) to - Preserve its Title (section 1) will typically require changing the - actual title. - - 9. TERMINATION - - You may not copy, modify, sublicense, or distribute the Document - except as expressly provided under this License. Any attempt - otherwise to copy, modify, sublicense, or distribute it is void, - and will automatically terminate your rights under this License. - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the - copyright holder fails to notify you of the violation by some - reasonable means prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from - that copyright holder, and you cure the violation prior to 30 days - after your receipt of the notice. - - Termination of your rights under this section does not terminate - the licenses of parties who have received copies or rights from you - under this License. If your rights have been terminated and not - permanently reinstated, receipt of a copy of some or all of the - same material does not give you any rights to use it. - - 10. FUTURE REVISIONS OF THIS LICENSE - - The Free Software Foundation may publish new, revised versions of - the GNU Free Documentation License from time to time. Such new - versions will be similar in spirit to the present version, but may - differ in detail to address new problems or concerns. See - . - - Each version of the License is given a distinguishing version - number. If the Document specifies that a particular numbered - version of this License “or any later version” applies to it, you - have the option of following the terms and conditions either of - that specified version or of any later version that has been - published (not as a draft) by the Free Software Foundation. If the - Document does not specify a version number of this License, you may - choose any version ever published (not as a draft) by the Free - Software Foundation. If the Document specifies that a proxy can - decide which future versions of this License can be used, that - proxy’s public statement of acceptance of a version permanently - authorizes you to choose that version for the Document. - - 11. RELICENSING - - “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any - World Wide Web server that publishes copyrightable works and also - provides prominent facilities for anybody to edit those works. A - public wiki that anybody can edit is an example of such a server. - A “Massive Multiauthor Collaboration” (or “MMC”) contained in the - site means any set of copyrightable works thus published on the MMC - site. - - “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 - license published by Creative Commons Corporation, a not-for-profit - corporation with a principal place of business in San Francisco, - California, as well as future copyleft versions of that license - published by that same organization. - - “Incorporate” means to publish or republish a Document, in whole or - in part, as part of another Document. - - An MMC is “eligible for relicensing” if it is licensed under this - License, and if all works that were first published under this - License somewhere other than this MMC, and subsequently - incorporated in whole or in part into the MMC, (1) had no cover - texts or invariant sections, and (2) were thus incorporated prior - to November 1, 2008. - - The operator of an MMC Site may republish an MMC contained in the - site under CC-BY-SA on the same site at any time before August 1, - 2009, provided the MMC is eligible for relicensing. - -ADDENDUM: How to use this License for your documents -==================================================== - -To use this License in a document you have written, include a copy of -the License in the document and put the following copyright and license -notices just after the title page: - - Copyright (C) YEAR YOUR NAME. - Permission is granted to copy, distribute and/or modify this document - under the terms of the GNU Free Documentation License, Version 1.3 - or any later version published by the Free Software Foundation; - with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - Texts. A copy of the license is included in the section entitled ``GNU - Free Documentation License''. - - If you have Invariant Sections, Front-Cover Texts and Back-Cover -Texts, replace the “with...Texts.” line with this: - - with the Invariant Sections being LIST THEIR TITLES, with - the Front-Cover Texts being LIST, and with the Back-Cover Texts - being LIST. - - If you have Invariant Sections without Cover Texts, or some other -combination of the three, merge those two alternatives to suit the -situation. - - If your document contains nontrivial examples of program code, we -recommend releasing these examples in parallel under your choice of free -software license, such as the GNU General Public License, to permit -their use in free software. - - -File: dash.info, Node: GPL, Next: Index, Prev: FDL, Up: Top - -Appendix B GNU General Public License -************************************* - - Version 3, 29 June 2007 - - Copyright © 2007 Free Software Foundation, Inc. - - Everyone is permitted to copy and distribute verbatim copies of this - license document, but changing it is not allowed. - -Preamble -======== - -The GNU General Public License is a free, copyleft license for software -and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program—to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers’ and authors’ protection, the GPL clearly explains -that there is no warranty for this free software. For both users’ and -authors’ sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users’ freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - -TERMS AND CONDITIONS -==================== - - 0. Definitions. - - “This License” refers to version 3 of the GNU General Public - License. - - “Copyright” also means copyright-like laws that apply to other - kinds of works, such as semiconductor masks. - - “The Program” refers to any copyrightable work licensed under this - License. Each licensee is addressed as “you”. “Licensees” and - “recipients” may be individuals or organizations. - - To “modify” a work means to copy from or adapt all or part of the - work in a fashion requiring copyright permission, other than the - making of an exact copy. The resulting work is called a “modified - version” of the earlier work or a work “based on” the earlier work. - - A “covered work” means either the unmodified Program or a work - based on the Program. - - To “propagate” a work means to do anything with it that, without - permission, would make you directly or secondarily liable for - infringement under applicable copyright law, except executing it on - a computer or modifying a private copy. Propagation includes - copying, distribution (with or without modification), making - available to the public, and in some countries other activities as - well. - - To “convey” a work means any kind of propagation that enables other - parties to make or receive copies. Mere interaction with a user - through a computer network, with no transfer of a copy, is not - conveying. - - An interactive user interface displays “Appropriate Legal Notices” - to the extent that it includes a convenient and prominently visible - feature that (1) displays an appropriate copyright notice, and (2) - tells the user that there is no warranty for the work (except to - the extent that warranties are provided), that licensees may convey - the work under this License, and how to view a copy of this - License. If the interface presents a list of user commands or - options, such as a menu, a prominent item in the list meets this - criterion. - - 1. Source Code. - - The “source code” for a work means the preferred form of the work - for making modifications to it. “Object code” means any non-source - form of a work. - - A “Standard Interface” means an interface that either is an - official standard defined by a recognized standards body, or, in - the case of interfaces specified for a particular programming - language, one that is widely used among developers working in that - language. - - The “System Libraries” of an executable work include anything, - other than the work as a whole, that (a) is included in the normal - form of packaging a Major Component, but which is not part of that - Major Component, and (b) serves only to enable use of the work with - that Major Component, or to implement a Standard Interface for - which an implementation is available to the public in source code - form. A “Major Component”, in this context, means a major - essential component (kernel, window system, and so on) of the - specific operating system (if any) on which the executable work - runs, or a compiler used to produce the work, or an object code - interpreter used to run it. - - The “Corresponding Source” for a work in object code form means all - the source code needed to generate, install, and (for an executable - work) run the object code and to modify the work, including scripts - to control those activities. However, it does not include the - work’s System Libraries, or general-purpose tools or generally - available free programs which are used unmodified in performing - those activities but which are not part of the work. For example, - Corresponding Source includes interface definition files associated - with source files for the work, and the source code for shared - libraries and dynamically linked subprograms that the work is - specifically designed to require, such as by intimate data - communication or control flow between those subprograms and other - parts of the work. - - The Corresponding Source need not include anything that users can - regenerate automatically from other parts of the Corresponding - Source. - - The Corresponding Source for a work in source code form is that - same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of - copyright on the Program, and are irrevocable provided the stated - conditions are met. This License explicitly affirms your unlimited - permission to run the unmodified Program. The output from running - a covered work is covered by this License only if the output, given - its content, constitutes a covered work. This License acknowledges - your rights of fair use or other equivalent, as provided by - copyright law. - - You may make, run and propagate covered works that you do not - convey, without conditions so long as your license otherwise - remains in force. You may convey covered works to others for the - sole purpose of having them make modifications exclusively for you, - or provide you with facilities for running those works, provided - that you comply with the terms of this License in conveying all - material for which you do not control copyright. Those thus making - or running the covered works for you must do so exclusively on your - behalf, under your direction and control, on terms that prohibit - them from making any copies of your copyrighted material outside - their relationship with you. - - Conveying under any other circumstances is permitted solely under - the conditions stated below. Sublicensing is not allowed; section - 10 makes it unnecessary. - - 3. Protecting Users’ Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological - measure under any applicable law fulfilling obligations under - article 11 of the WIPO copyright treaty adopted on 20 December - 1996, or similar laws prohibiting or restricting circumvention of - such measures. - - When you convey a covered work, you waive any legal power to forbid - circumvention of technological measures to the extent such - circumvention is effected by exercising rights under this License - with respect to the covered work, and you disclaim any intention to - limit operation or modification of the work as a means of - enforcing, against the work’s users, your or third parties’ legal - rights to forbid circumvention of technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program’s source code as you - receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice; - keep intact all notices stating that this License and any - non-permissive terms added in accord with section 7 apply to the - code; keep intact all notices of the absence of any warranty; and - give all recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, - and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to - produce it from the Program, in the form of source code under the - terms of section 4, provided that you also meet all of these - conditions: - - a. The work must carry prominent notices stating that you - modified it, and giving a relevant date. - - b. The work must carry prominent notices stating that it is - released under this License and any conditions added under - section 7. This requirement modifies the requirement in - section 4 to “keep intact all notices”. - - c. You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable - section 7 additional terms, to the whole of the work, and all - its parts, regardless of how they are packaged. This License - gives no permission to license the work in any other way, but - it does not invalidate such permission if you have separately - received it. - - d. If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has - interactive interfaces that do not display Appropriate Legal - Notices, your work need not make them do so. - - A compilation of a covered work with other separate and independent - works, which are not by their nature extensions of the covered - work, and which are not combined with it such as to form a larger - program, in or on a volume of a storage or distribution medium, is - called an “aggregate” if the compilation and its resulting - copyright are not used to limit the access or legal rights of the - compilation’s users beyond what the individual works permit. - Inclusion of a covered work in an aggregate does not cause this - License to apply to the other parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms - of sections 4 and 5, provided that you also convey the - machine-readable Corresponding Source under the terms of this - License, in one of these ways: - - a. Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b. Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that - product model, to give anyone who possesses the object code - either (1) a copy of the Corresponding Source for all the - software in the product that is covered by this License, on a - durable physical medium customarily used for software - interchange, for a price no more than your reasonable cost of - physically performing this conveying of source, or (2) access - to copy the Corresponding Source from a network server at no - charge. - - c. Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, - and only if you received the object code with such an offer, - in accord with subsection 6b. - - d. Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to - the Corresponding Source in the same way through the same - place at no further charge. You need not require recipients - to copy the Corresponding Source along with the object code. - If the place to copy the object code is a network server, the - Corresponding Source may be on a different server (operated by - you or a third party) that supports equivalent copying - facilities, provided you maintain clear directions next to the - object code saying where to find the Corresponding Source. - Regardless of what server hosts the Corresponding Source, you - remain obligated to ensure that it is available for as long as - needed to satisfy these requirements. - - e. Convey the object code using peer-to-peer transmission, - provided you inform other peers where the object code and - Corresponding Source of the work are being offered to the - general public at no charge under subsection 6d. - - A separable portion of the object code, whose source code is - excluded from the Corresponding Source as a System Library, need - not be included in conveying the object code work. - - A “User Product” is either (1) a “consumer product”, which means - any tangible personal property which is normally used for personal, - family, or household purposes, or (2) anything designed or sold for - incorporation into a dwelling. In determining whether a product is - a consumer product, doubtful cases shall be resolved in favor of - coverage. For a particular product received by a particular user, - “normally used” refers to a typical or common use of that class of - product, regardless of the status of the particular user or of the - way in which the particular user actually uses, or expects or is - expected to use, the product. A product is a consumer product - regardless of whether the product has substantial commercial, - industrial or non-consumer uses, unless such uses represent the - only significant mode of use of the product. - - “Installation Information” for a User Product means any methods, - procedures, authorization keys, or other information required to - install and execute modified versions of a covered work in that - User Product from a modified version of its Corresponding Source. - The information must suffice to ensure that the continued - functioning of the modified object code is in no case prevented or - interfered with solely because modification has been made. - - If you convey an object code work under this section in, or with, - or specifically for use in, a User Product, and the conveying - occurs as part of a transaction in which the right of possession - and use of the User Product is transferred to the recipient in - perpetuity or for a fixed term (regardless of how the transaction - is characterized), the Corresponding Source conveyed under this - section must be accompanied by the Installation Information. But - this requirement does not apply if neither you nor any third party - retains the ability to install modified object code on the User - Product (for example, the work has been installed in ROM). - - The requirement to provide Installation Information does not - include a requirement to continue to provide support service, - warranty, or updates for a work that has been modified or installed - by the recipient, or for the User Product in which it has been - modified or installed. Access to a network may be denied when the - modification itself materially and adversely affects the operation - of the network or violates the rules and protocols for - communication across the network. - - Corresponding Source conveyed, and Installation Information - provided, in accord with this section must be in a format that is - publicly documented (and with an implementation available to the - public in source code form), and must require no special password - or key for unpacking, reading or copying. - - 7. Additional Terms. - - “Additional permissions” are terms that supplement the terms of - this License by making exceptions from one or more of its - conditions. Additional permissions that are applicable to the - entire Program shall be treated as though they were included in - this License, to the extent that they are valid under applicable - law. If additional permissions apply only to part of the Program, - that part may be used separately under those permissions, but the - entire Program remains governed by this License without regard to - the additional permissions. - - When you convey a copy of a covered work, you may at your option - remove any additional permissions from that copy, or from any part - of it. (Additional permissions may be written to require their own - removal in certain cases when you modify the work.) You may place - additional permissions on material, added by you to a covered work, - for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material - you add to a covered work, you may (if authorized by the copyright - holders of that material) supplement the terms of this License with - terms: - - a. Disclaiming warranty or limiting liability differently from - the terms of sections 15 and 16 of this License; or - - b. Requiring preservation of specified reasonable legal notices - or author attributions in that material or in the Appropriate - Legal Notices displayed by works containing it; or - - c. Prohibiting misrepresentation of the origin of that material, - or requiring that modified versions of such material be marked - in reasonable ways as different from the original version; or - - d. Limiting the use for publicity purposes of names of licensors - or authors of the material; or - - e. Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f. Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified - versions of it) with contractual assumptions of liability to - the recipient, for any liability that these contractual - assumptions directly impose on those licensors and authors. - - All other non-permissive additional terms are considered “further - restrictions” within the meaning of section 10. If the Program as - you received it, or any part of it, contains a notice stating that - it is governed by this License along with a term that is a further - restriction, you may remove that term. If a license document - contains a further restriction but permits relicensing or conveying - under this License, you may add to a covered work material governed - by the terms of that license document, provided that the further - restriction does not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you - must place, in the relevant source files, a statement of the - additional terms that apply to those files, or a notice indicating - where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in - the form of a separately written license, or stated as exceptions; - the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly - provided under this License. Any attempt otherwise to propagate or - modify it is void, and will automatically terminate your rights - under this License (including any patent licenses granted under the - third paragraph of section 11). - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the - copyright holder fails to notify you of the violation by some - reasonable means prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from - that copyright holder, and you cure the violation prior to 30 days - after your receipt of the notice. - - Termination of your rights under this section does not terminate - the licenses of parties who have received copies or rights from you - under this License. If your rights have been terminated and not - permanently reinstated, you do not qualify to receive new licenses - for the same material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or - run a copy of the Program. Ancillary propagation of a covered work - occurring solely as a consequence of using peer-to-peer - transmission to receive a copy likewise does not require - acceptance. However, nothing other than this License grants you - permission to propagate or modify any covered work. These actions - infringe copyright if you do not accept this License. Therefore, - by modifying or propagating a covered work, you indicate your - acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically - receives a license from the original licensors, to run, modify and - propagate that work, subject to this License. You are not - responsible for enforcing compliance by third parties with this - License. - - An “entity transaction” is a transaction transferring control of an - organization, or substantially all assets of one, or subdividing an - organization, or merging organizations. If propagation of a - covered work results from an entity transaction, each party to that - transaction who receives a copy of the work also receives whatever - licenses to the work the party’s predecessor in interest had or - could give under the previous paragraph, plus a right to possession - of the Corresponding Source of the work from the predecessor in - interest, if the predecessor has it or can get it with reasonable - efforts. - - You may not impose any further restrictions on the exercise of the - rights granted or affirmed under this License. For example, you - may not impose a license fee, royalty, or other charge for exercise - of rights granted under this License, and you may not initiate - litigation (including a cross-claim or counterclaim in a lawsuit) - alleging that any patent claim is infringed by making, using, - selling, offering for sale, or importing the Program or any portion - of it. - - 11. Patents. - - A “contributor” is a copyright holder who authorizes use under this - License of the Program or a work on which the Program is based. - The work thus licensed is called the contributor’s “contributor - version”. - - A contributor’s “essential patent claims” are all patent claims - owned or controlled by the contributor, whether already acquired or - hereafter acquired, that would be infringed by some manner, - permitted by this License, of making, using, or selling its - contributor version, but do not include claims that would be - infringed only as a consequence of further modification of the - contributor version. For purposes of this definition, “control” - includes the right to grant patent sublicenses in a manner - consistent with the requirements of this License. - - Each contributor grants you a non-exclusive, worldwide, - royalty-free patent license under the contributor’s essential - patent claims, to make, use, sell, offer for sale, import and - otherwise run, modify and propagate the contents of its contributor - version. - - In the following three paragraphs, a “patent license” is any - express agreement or commitment, however denominated, not to - enforce a patent (such as an express permission to practice a - patent or covenant not to sue for patent infringement). To “grant” - such a patent license to a party means to make such an agreement or - commitment not to enforce a patent against the party. - - If you convey a covered work, knowingly relying on a patent - license, and the Corresponding Source of the work is not available - for anyone to copy, free of charge and under the terms of this - License, through a publicly available network server or other - readily accessible means, then you must either (1) cause the - Corresponding Source to be so available, or (2) arrange to deprive - yourself of the benefit of the patent license for this particular - work, or (3) arrange, in a manner consistent with the requirements - of this License, to extend the patent license to downstream - recipients. “Knowingly relying” means you have actual knowledge - that, but for the patent license, your conveying the covered work - in a country, or your recipient’s use of the covered work in a - country, would infringe one or more identifiable patents in that - country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or - arrangement, you convey, or propagate by procuring conveyance of, a - covered work, and grant a patent license to some of the parties - receiving the covered work authorizing them to use, propagate, - modify or convey a specific copy of the covered work, then the - patent license you grant is automatically extended to all - recipients of the covered work and works based on it. - - A patent license is “discriminatory” if it does not include within - the scope of its coverage, prohibits the exercise of, or is - conditioned on the non-exercise of one or more of the rights that - are specifically granted under this License. You may not convey a - covered work if you are a party to an arrangement with a third - party that is in the business of distributing software, under which - you make payment to the third party based on the extent of your - activity of conveying the work, and under which the third party - grants, to any of the parties who would receive the covered work - from you, a discriminatory patent license (a) in connection with - copies of the covered work conveyed by you (or copies made from - those copies), or (b) primarily for and in connection with specific - products or compilations that contain the covered work, unless you - entered into that arrangement, or that patent license was granted, - prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting - any implied license or other defenses to infringement that may - otherwise be available to you under applicable patent law. - - 12. No Surrender of Others’ Freedom. - - If conditions are imposed on you (whether by court order, agreement - or otherwise) that contradict the conditions of this License, they - do not excuse you from the conditions of this License. If you - cannot convey a covered work so as to satisfy simultaneously your - obligations under this License and any other pertinent obligations, - then as a consequence you may not convey it at all. For example, - if you agree to terms that obligate you to collect a royalty for - further conveying from those to whom you convey the Program, the - only way you could satisfy both those terms and this License would - be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have - permission to link or combine any covered work with a work licensed - under version 3 of the GNU Affero General Public License into a - single combined work, and to convey the resulting work. The terms - of this License will continue to apply to the part which is the - covered work, but the special requirements of the GNU Affero - General Public License, section 13, concerning interaction through - a network will apply to the combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new - versions of the GNU General Public License from time to time. Such - new versions will be similar in spirit to the present version, but - may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the - Program specifies that a certain numbered version of the GNU - General Public License “or any later version” applies to it, you - have the option of following the terms and conditions either of - that numbered version or of any later version published by the Free - Software Foundation. If the Program does not specify a version - number of the GNU General Public License, you may choose any - version ever published by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future - versions of the GNU General Public License can be used, that - proxy’s public statement of acceptance of a version permanently - authorizes you to choose that version for the Program. - - Later license versions may give you additional or different - permissions. However, no additional obligations are imposed on any - author or copyright holder as a result of your choosing to follow a - later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY - APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE - COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE - RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. - SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL - NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN - WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES - AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR - DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR - CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE - THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA - BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD - PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER - PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF - THE POSSIBILITY OF SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided - above cannot be given local legal effect according to their terms, - reviewing courts shall apply local law that most closely - approximates an absolute waiver of all civil liability in - connection with the Program, unless a warranty or assumption of - liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS -=========================== - -How to Apply These Terms to Your New Programs -============================================= - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least the -“copyright” line and a pointer to where the full notice is found. - - ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. - Copyright (C) YEAR NAME OF AUTHOR - - 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 . - - Also add information on how to contact you by electronic and paper -mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - PROGRAM Copyright (C) YEAR NAME OF AUTHOR - This program comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’. - This is free software, and you are welcome to redistribute it - under certain conditions; type ‘show c’ for details. - - The hypothetical commands ‘show w’ and ‘show c’ should show the -appropriate parts of the General Public License. Of course, your -program’s commands might be different; for a GUI interface, you would -use an “about box”. - - You should also get your employer (if you work as a programmer) or -school, if any, to sign a “copyright disclaimer” for the program, if -necessary. For more information on this, and how to apply and follow -the GNU GPL, see . - - The GNU General Public License does not permit incorporating your -program into proprietary programs. If your program is a subroutine -library, you may consider it more useful to permit linking proprietary -applications with the library. If this is what you want to do, use the -GNU Lesser General Public License instead of this License. But first, -please read . - - -File: dash.info, Node: Index, Prev: GPL, Up: Top - -Index -***** - -[index] -* Menu: - -* !cdr: Destructive operations. - (line 16) -* !cons: Destructive operations. - (line 8) -* -->: Threading macros. (line 35) -* ->: Threading macros. (line 9) -* ->>: Threading macros. (line 22) -* -all?: Predicates. (line 53) -* -andfn: Function combinators. - (line 184) -* -annotate: Maps. (line 86) -* -any?: Predicates. (line 41) -* -applify: Function combinators. - (line 63) -* -as->: Threading macros. (line 49) -* -butlast: Other list operations. - (line 405) -* -clone: Tree operations. (line 123) -* -common-prefix: Reductions. (line 242) -* -common-suffix: Reductions. (line 252) -* -compose: Function combinators. - (line 49) -* -concat: List to list. (line 23) -* -cons*: Other list operations. - (line 19) -* -cons-pair?: Predicates. (line 154) -* -const: Function combinators. - (line 128) -* -contains?: Predicates. (line 100) -* -copy: Maps. (line 151) -* -count: Reductions. (line 172) -* -cut: Function combinators. - (line 140) -* -cycle: Unfolding. (line 55) -* -difference: Set operations. (line 22) -* -distinct: Set operations. (line 73) -* -dotimes: Side effects. (line 80) -* -doto: Threading macros. (line 99) -* -drop: Sublist selection. (line 149) -* -drop-last: Sublist selection. (line 163) -* -drop-while: Sublist selection. (line 194) -* -each: Side effects. (line 8) -* -each-indexed: Side effects. (line 38) -* -each-r: Side effects. (line 52) -* -each-r-while: Side effects. (line 65) -* -each-while: Side effects. (line 24) -* -elem-index: Indexing. (line 9) -* -elem-indices: Indexing. (line 23) -* -every: Predicates. (line 23) -* -fifth-item: Other list operations. - (line 380) -* -filter: Sublist selection. (line 8) -* -find-index: Indexing. (line 35) -* -find-indices: Indexing. (line 73) -* -find-last-index: Indexing. (line 54) -* -first: Other list operations. - (line 300) -* -first-item: Other list operations. - (line 328) -* -fix: Other list operations. - (line 445) -* -fixfn: Function combinators. - (line 224) -* -flatten: List to list. (line 38) -* -flatten-n: List to list. (line 60) -* -flip: Function combinators. - (line 95) -* -fourth-item: Other list operations. - (line 367) -* -frequencies: Reductions. (line 310) -* -grade-down: Indexing. (line 103) -* -grade-up: Indexing. (line 93) -* -group-by: Partitioning. (line 205) -* -if-let: Binding. (line 34) -* -if-let*: Binding. (line 45) -* -inits: Reductions. (line 222) -* -insert-at: List to list. (line 114) -* -interleave: Other list operations. - (line 56) -* -interpose: Other list operations. - (line 46) -* -intersection: Set operations. (line 36) -* -iota: Other list operations. - (line 67) -* -is-infix?: Predicates. (line 140) -* -is-prefix?: Predicates. (line 116) -* -is-suffix?: Predicates. (line 128) -* -iterate: Unfolding. (line 9) -* -iteratefn: Function combinators. - (line 201) -* -juxt: Function combinators. - (line 37) -* -keep: List to list. (line 8) -* -lambda: Binding. (line 247) -* -last: Other list operations. - (line 318) -* -last-item: Other list operations. - (line 393) -* -let: Binding. (line 61) -* -let*: Binding. (line 227) -* -list: Other list operations. - (line 428) -* -map: Maps. (line 10) -* -map-first: Maps. (line 38) -* -map-indexed: Maps. (line 68) -* -map-last: Maps. (line 53) -* -map-when: Maps. (line 22) -* -mapcat: Maps. (line 140) -* -max: Reductions. (line 286) -* -max-by: Reductions. (line 296) -* -min: Reductions. (line 262) -* -min-by: Reductions. (line 272) -* -non-nil: Sublist selection. (line 95) -* -none?: Predicates. (line 73) -* -not: Function combinators. - (line 153) -* -on: Function combinators. - (line 75) -* -only-some?: Predicates. (line 85) -* -orfn: Function combinators. - (line 167) -* -pad: Other list operations. - (line 241) -* -partial: Function combinators. - (line 8) -* -partition: Partitioning. (line 90) -* -partition-after-item: Partitioning. (line 195) -* -partition-after-pred: Partitioning. (line 162) -* -partition-all: Partitioning. (line 102) -* -partition-all-in-steps: Partitioning. (line 126) -* -partition-before-item: Partitioning. (line 185) -* -partition-before-pred: Partitioning. (line 174) -* -partition-by: Partitioning. (line 138) -* -partition-by-header: Partitioning. (line 149) -* -partition-in-steps: Partitioning. (line 113) -* -permutations: Set operations. (line 60) -* -powerset: Set operations. (line 50) -* -prodfn: Function combinators. - (line 258) -* -product: Reductions. (line 201) -* -reduce: Reductions. (line 53) -* -reduce-from: Reductions. (line 8) -* -reduce-r: Reductions. (line 72) -* -reduce-r-from: Reductions. (line 26) -* -reductions: Reductions. (line 136) -* -reductions-from: Reductions. (line 100) -* -reductions-r: Reductions. (line 154) -* -reductions-r-from: Reductions. (line 118) -* -remove: Sublist selection. (line 26) -* -remove-at: List to list. (line 151) -* -remove-at-indices: List to list. (line 170) -* -remove-first: Sublist selection. (line 44) -* -remove-item: Sublist selection. (line 84) -* -remove-last: Sublist selection. (line 65) -* -repeat: Unfolding. (line 44) -* -replace: List to list. (line 72) -* -replace-at: List to list. (line 125) -* -replace-first: List to list. (line 86) -* -replace-last: List to list. (line 100) -* -rotate: Other list operations. - (line 8) -* -rotate-args: Function combinators. - (line 112) -* -rpartial: Function combinators. - (line 22) -* -running-product: Reductions. (line 211) -* -running-sum: Reductions. (line 190) -* -same-items?: Set operations. (line 88) -* -second-item: Other list operations. - (line 341) -* -select-by-indices: Sublist selection. (line 211) -* -select-column: Sublist selection. (line 241) -* -select-columns: Sublist selection. (line 222) -* -separate: Partitioning. (line 75) -* -setq: Binding. (line 270) -* -slice: Sublist selection. (line 105) -* -snoc: Other list operations. - (line 32) -* -some: Predicates. (line 8) -* -some-->: Threading macros. (line 86) -* -some->: Threading macros. (line 62) -* -some->>: Threading macros. (line 74) -* -sort: Other list operations. - (line 415) -* -splice: Maps. (line 102) -* -splice-list: Maps. (line 127) -* -split-at: Partitioning. (line 8) -* -split-on: Partitioning. (line 40) -* -split-when: Partitioning. (line 58) -* -split-with: Partitioning. (line 23) -* -sum: Reductions. (line 180) -* -table: Other list operations. - (line 256) -* -table-flat: Other list operations. - (line 275) -* -tails: Reductions. (line 232) -* -take: Sublist selection. (line 121) -* -take-last: Sublist selection. (line 135) -* -take-while: Sublist selection. (line 177) -* -third-item: Other list operations. - (line 354) -* -tree-map: Tree operations. (line 28) -* -tree-map-nodes: Tree operations. (line 39) -* -tree-mapreduce: Tree operations. (line 85) -* -tree-mapreduce-from: Tree operations. (line 104) -* -tree-reduce: Tree operations. (line 53) -* -tree-reduce-from: Tree operations. (line 70) -* -tree-seq: Tree operations. (line 8) -* -unfold: Unfolding. (line 25) -* -union: Set operations. (line 8) -* -unzip: Other list operations. - (line 215) -* -unzip-lists: Other list operations. - (line 196) -* -update-at: List to list. (line 137) -* -when-let: Binding. (line 9) -* -when-let*: Binding. (line 21) -* -zip: Other list operations. - (line 150) -* -zip-fill: Other list operations. - (line 176) -* -zip-lists: Other list operations. - (line 114) -* -zip-lists-fill: Other list operations. - (line 135) -* -zip-pair: Other list operations. - (line 98) -* -zip-with: Other list operations. - (line 80) -* dash-fontify-mode: Fontification of special variables. - (line 6) -* dash-register-info-lookup: Info symbol lookup. (line 6) -* global-dash-fontify-mode: Fontification of special variables. - (line 12) - - - -Tag Table: -Node: Top742 -Node: Installation2397 -Node: Using in a package3159 -Node: Fontification of special variables3504 -Node: Info symbol lookup4294 -Node: Functions4877 -Node: Maps6361 -Ref: -map6658 -Ref: -map-when7031 -Ref: -map-first7605 -Ref: -map-last8200 -Ref: -map-indexed8790 -Ref: -annotate9476 -Ref: -splice10080 -Ref: -splice-list11155 -Ref: -mapcat11614 -Ref: -copy11987 -Node: Sublist selection12175 -Ref: -filter12368 -Ref: -remove12921 -Ref: -remove-first13470 -Ref: -remove-last14318 -Ref: -remove-item15048 -Ref: -non-nil15448 -Ref: -slice15730 -Ref: -take16259 -Ref: -take-last16677 -Ref: -drop17114 -Ref: -drop-last17561 -Ref: -take-while17993 -Ref: -drop-while18620 -Ref: -select-by-indices19253 -Ref: -select-columns19764 -Ref: -select-column20467 -Node: List to list20930 -Ref: -keep21122 -Ref: -concat21698 -Ref: -flatten22226 -Ref: -flatten-n22988 -Ref: -replace23372 -Ref: -replace-first23833 -Ref: -replace-last24328 -Ref: -insert-at24816 -Ref: -replace-at25141 -Ref: -update-at25528 -Ref: -remove-at26069 -Ref: -remove-at-indices26696 -Node: Reductions27386 -Ref: -reduce-from27582 -Ref: -reduce-r-from28306 -Ref: -reduce29569 -Ref: -reduce-r30320 -Ref: -reductions-from31598 -Ref: -reductions-r-from32404 -Ref: -reductions33234 -Ref: -reductions-r33945 -Ref: -count34690 -Ref: -sum34920 -Ref: -running-sum35108 -Ref: -product35429 -Ref: -running-product35637 -Ref: -inits35978 -Ref: -tails36223 -Ref: -common-prefix36468 -Ref: -common-suffix36762 -Ref: -min37056 -Ref: -min-by37282 -Ref: -max37803 -Ref: -max-by38028 -Ref: -frequencies38554 -Node: Unfolding39169 -Ref: -iterate39410 -Ref: -unfold39857 -Ref: -repeat40662 -Ref: -cycle40946 -Node: Predicates41343 -Ref: -some41520 -Ref: -every41949 -Ref: -any?42663 -Ref: -all?43012 -Ref: -none?43754 -Ref: -only-some?44074 -Ref: -contains?44619 -Ref: -is-prefix?45125 -Ref: -is-suffix?45457 -Ref: -is-infix?45789 -Ref: -cons-pair?46149 -Node: Partitioning46480 -Ref: -split-at46668 -Ref: -split-with47332 -Ref: -split-on47972 -Ref: -split-when48643 -Ref: -separate49286 -Ref: -partition49820 -Ref: -partition-all50269 -Ref: -partition-in-steps50694 -Ref: -partition-all-in-steps51240 -Ref: -partition-by51754 -Ref: -partition-by-header52132 -Ref: -partition-after-pred52733 -Ref: -partition-before-pred53186 -Ref: -partition-before-item53571 -Ref: -partition-after-item53878 -Ref: -group-by54180 -Node: Indexing54613 -Ref: -elem-index54815 -Ref: -elem-indices55302 -Ref: -find-index55761 -Ref: -find-last-index56430 -Ref: -find-indices57081 -Ref: -grade-up57843 -Ref: -grade-down58250 -Node: Set operations58664 -Ref: -union58847 -Ref: -difference59277 -Ref: -intersection59705 -Ref: -powerset60134 -Ref: -permutations60411 -Ref: -distinct60849 -Ref: -same-items?61243 -Node: Other list operations61852 -Ref: -rotate62077 -Ref: -cons*62430 -Ref: -snoc62852 -Ref: -interpose63264 -Ref: -interleave63558 -Ref: -iota63924 -Ref: -zip-with64407 -Ref: -zip-pair65215 -Ref: -zip-lists65781 -Ref: -zip-lists-fill66579 -Ref: -zip67289 -Ref: -zip-fill68316 -Ref: -unzip-lists69230 -Ref: -unzip69853 -Ref: -pad70846 -Ref: -table71331 -Ref: -table-flat72117 -Ref: -first73122 -Ref: -last73655 -Ref: -first-item74001 -Ref: -second-item74413 -Ref: -third-item74830 -Ref: -fourth-item75205 -Ref: -fifth-item75583 -Ref: -last-item75958 -Ref: -butlast76319 -Ref: -sort76564 -Ref: -list77058 -Ref: -fix77627 -Node: Tree operations78116 -Ref: -tree-seq78312 -Ref: -tree-map79173 -Ref: -tree-map-nodes79613 -Ref: -tree-reduce80477 -Ref: -tree-reduce-from81359 -Ref: -tree-mapreduce81959 -Ref: -tree-mapreduce-from82818 -Ref: -clone84103 -Node: Threading macros84441 -Ref: ->84666 -Ref: ->>85154 -Ref: -->85657 -Ref: -as->86213 -Ref: -some->86667 -Ref: -some->>87052 -Ref: -some-->87499 -Ref: -doto88066 -Node: Binding88619 -Ref: -when-let88826 -Ref: -when-let*89287 -Ref: -if-let89816 -Ref: -if-let*90182 -Ref: -let90805 -Ref: -let*96895 -Ref: -lambda97832 -Ref: -setq98638 -Node: Side effects99439 -Ref: -each99633 -Ref: -each-while100160 -Ref: -each-indexed100780 -Ref: -each-r101372 -Ref: -each-r-while101814 -Ref: -dotimes102458 -Node: Destructive operations103011 -Ref: !cons103229 -Ref: !cdr103433 -Node: Function combinators103626 -Ref: -partial103830 -Ref: -rpartial104348 -Ref: -juxt104996 -Ref: -compose105448 -Ref: -applify106055 -Ref: -on106485 -Ref: -flip107257 -Ref: -rotate-args107781 -Ref: -const108410 -Ref: -cut108752 -Ref: -not109232 -Ref: -orfn109776 -Ref: -andfn110569 -Ref: -iteratefn111356 -Ref: -fixfn112058 -Ref: -prodfn113632 -Node: Development114783 -Node: Contribute115072 -Node: Contributors116084 -Node: FDL118177 -Node: GPL143497 -Node: Index181246 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/elpa/dash-20230714.723/dir b/elpa/dash-20230714.723/dir deleted file mode 100644 index 7d473f49..00000000 --- a/elpa/dash-20230714.723/dir +++ /dev/null @@ -1,18 +0,0 @@ -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" 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. diff --git a/elpa/dash-20240510.1327/dash-autoloads.el b/elpa/dash-20240510.1327/dash-autoloads.el new file mode 100644 index 00000000..f9084138 --- /dev/null +++ b/elpa/dash-20240510.1327/dash-autoloads.el @@ -0,0 +1,83 @@ +;;; dash-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from dash.el + +(autoload 'dash-fontify-mode "dash" "\ +Toggle fontification of Dash special variables. + +Dash-Fontify mode is a buffer-local minor mode intended for Emacs +Lisp buffers. Enabling it causes the special variables bound in +anaphoric Dash macros to be fontified. These anaphoras include +`it', `it-index', `acc', and `other'. In older Emacs versions +which do not dynamically detect macros, Dash-Fontify mode +additionally fontifies Dash macro calls. + +See also `dash-fontify-mode-lighter' and +`global-dash-fontify-mode'. + +This is a minor mode. If called interactively, toggle the +`Dash-Fontify mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `dash-fontify-mode'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +(fn &optional ARG)" t) +(put 'global-dash-fontify-mode 'globalized-minor-mode t) +(defvar global-dash-fontify-mode nil "\ +Non-nil if Global Dash-Fontify mode is enabled. +See the `global-dash-fontify-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-dash-fontify-mode'.") +(custom-autoload 'global-dash-fontify-mode "dash" nil) +(autoload 'global-dash-fontify-mode "dash" "\ +Toggle Dash-Fontify mode in all buffers. +With prefix ARG, enable Global Dash-Fontify mode if ARG is positive; +otherwise, disable it. + +If called from Lisp, toggle the mode if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +Dash-Fontify mode is enabled in all buffers where +`dash--turn-on-fontify-mode' would do it. + +See `dash-fontify-mode' for more information on Dash-Fontify mode. + +(fn &optional ARG)" t) +(autoload 'dash-register-info-lookup "dash" "\ +Register the Dash Info manual with `info-lookup-symbol'. +This allows Dash symbols to be looked up with \\[info-lookup-symbol]." t) +(register-definition-prefixes "dash" '("!cdr" "!cons" "--" "->" "-a" "-butlast" "-c" "-d" "-e" "-f" "-gr" "-i" "-juxt" "-keep" "-l" "-m" "-no" "-o" "-p" "-r" "-s" "-t" "-u" "-value-to-list" "-when-let" "-zip" "dash-")) + +;;; End of scraped data + +(provide 'dash-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; dash-autoloads.el ends here diff --git a/elpa/dash-20240510.1327/dash-pkg.el b/elpa/dash-20240510.1327/dash-pkg.el new file mode 100644 index 00000000..6b4ebeff --- /dev/null +++ b/elpa/dash-20240510.1327/dash-pkg.el @@ -0,0 +1,14 @@ +(define-package "dash" "20240510.1327" "A modern list library for Emacs" + '((emacs "24")) + :commit "1de9dcb83eacfb162b6d9a118a4770b1281bcd84" :authors + '(("Magnar Sveen" . "magnars@gmail.com")) + :maintainers + '(("Magnar Sveen" . "magnars@gmail.com")) + :maintainer + '("Magnar Sveen" . "magnars@gmail.com") + :keywords + '("extensions" "lisp") + :url "https://github.com/magnars/dash.el") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/dash-20240510.1327/dash.el b/elpa/dash-20240510.1327/dash.el new file mode 100644 index 00000000..ed2a8592 --- /dev/null +++ b/elpa/dash-20240510.1327/dash.el @@ -0,0 +1,4136 @@ +;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2024 Free Software Foundation, Inc. + +;; Author: Magnar Sveen +;; Version: 2.19.1 +;; Package-Requires: ((emacs "24")) +;; Keywords: extensions, lisp +;; Homepage: https://github.com/magnars/dash.el + +;; 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 . + +;;; Commentary: + +;; A modern list API for Emacs. +;; +;; See its overview at https://github.com/magnars/dash.el#functions. + +;;; Code: + +(eval-when-compile + ;; TODO: Emacs 24.3 first introduced `gv', so remove this and all + ;; calls to `defsetf' when support for earlier versions is dropped. + (unless (fboundp 'gv-define-setter) + (require 'cl)) + + ;; - 24.3 started complaining about unknown `declare' props. + ;; - 25 introduced `pure' and `side-effect-free'. + ;; - 30 introduced `important-return-value'. + (when (boundp 'defun-declarations-alist) + (dolist (prop '(important-return-value pure side-effect-free)) + (unless (assq prop defun-declarations-alist) + (push (list prop #'ignore) defun-declarations-alist))))) + +(defgroup dash () + "Customize group for Dash, a modern list library." + :group 'extensions + :group 'lisp + :prefix "dash-") + +(defmacro !cons (car cdr) + "Destructive: Set CDR to the cons of CAR and CDR." + (declare (debug (form symbolp))) + `(setq ,cdr (cons ,car ,cdr))) + +(defmacro !cdr (list) + "Destructive: Set LIST to the cdr of LIST." + (declare (debug (symbolp))) + `(setq ,list (cdr ,list))) + +(defmacro --each (list &rest body) + "Evaluate BODY for each element of LIST and return nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating BODY. +This is the anaphoric counterpart to `-each'." + (declare (debug (form body)) (indent 1)) + (let ((l (make-symbol "list")) + (i (make-symbol "i"))) + `(let ((,l ,list) + (,i 0)) + (while ,l + (let ((it (pop ,l)) (it-index ,i)) + (ignore it it-index) + ,@body) + (setq ,i (1+ ,i)))))) + +(defun -each (list fn) + "Call FN on each element of LIST. +Return nil; this function is intended for side effects. + +Its anaphoric counterpart is `--each'. + +For access to the current element's index in LIST, see +`-each-indexed'." + (declare (indent 1)) + (ignore (mapc fn list))) + +(defalias '--each-indexed '--each) + +(defun -each-indexed (list fn) + "Call FN on each index and element of LIST. +For each ITEM at INDEX in LIST, call (funcall FN INDEX ITEM). +Return nil; this function is intended for side effects. + +See also: `-map-indexed'." + (declare (indent 1)) + (--each list (funcall fn it-index it))) + +(defmacro --each-while (list pred &rest body) + "Evaluate BODY for each item in LIST, while PRED evaluates to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating PRED or BODY. Once +an element is reached for which PRED evaluates to nil, no further +BODY is evaluated. The return value is always nil. +This is the anaphoric counterpart to `-each-while'." + (declare (debug (form form body)) (indent 2)) + (let ((l (make-symbol "list")) + (i (make-symbol "i")) + (elt (make-symbol "elt"))) + `(let ((,l ,list) + (,i 0) + ,elt) + (while (when ,l + (setq ,elt (car-safe ,l)) + (let ((it ,elt) (it-index ,i)) + (ignore it it-index) + ,pred)) + (let ((it ,elt) (it-index ,i)) + (ignore it it-index) + ,@body) + (setq ,i (1+ ,i) ,l (cdr ,l)))))) + +(defun -each-while (list pred fn) + "Call FN on each ITEM in LIST, while (PRED ITEM) is non-nil. +Once an ITEM is reached for which PRED returns nil, FN is no +longer called. Return nil; this function is intended for side +effects. + +Its anaphoric counterpart is `--each-while'." + (declare (indent 2)) + (--each-while list (funcall pred it) (funcall fn it))) + +(defmacro --each-r (list &rest body) + "Evaluate BODY for each element of LIST in reversed order. +Each element of LIST in turn, starting at its end, is bound to +`it' and its index within LIST to `it-index' before evaluating +BODY. The return value is always nil. +This is the anaphoric counterpart to `-each-r'." + (declare (debug (form body)) (indent 1)) + (let ((v (make-symbol "vector")) + (i (make-symbol "i"))) + ;; Implementation note: building a 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 the modification was undone before we return. + `(let* ((,v (vconcat ,list)) + (,i (length ,v)) + it it-index) + (ignore it it-index) + (while (> ,i 0) + (setq ,i (1- ,i) it-index ,i it (aref ,v ,i)) + ,@body)))) + +(defun -each-r (list fn) + "Call FN on each element of LIST in reversed order. +Return nil; this function is intended for side effects. + +Its anaphoric counterpart is `--each-r'." + (--each-r list (funcall fn it))) + +(defmacro --each-r-while (list pred &rest body) + "Eval BODY for each item in reversed LIST, while PRED evals to non-nil. +Each element of LIST in turn, starting at its end, is bound to +`it' and its index within LIST to `it-index' before evaluating +PRED or BODY. Once an element is reached for which PRED +evaluates to nil, no further BODY is evaluated. The return value +is always nil. +This is the anaphoric counterpart to `-each-r-while'." + (declare (debug (form form body)) (indent 2)) + (let ((v (make-symbol "vector")) + (i (make-symbol "i")) + (elt (make-symbol "elt"))) + `(let* ((,v (vconcat ,list)) + (,i (length ,v)) + ,elt it it-index) + (ignore it it-index) + (while (when (> ,i 0) + (setq ,i (1- ,i) it-index ,i) + (setq ,elt (aref ,v ,i) it ,elt) + ,pred) + (setq it-index ,i it ,elt) + ,@body)))) + +(defun -each-r-while (list pred fn) + "Call FN on each ITEM in reversed LIST, while (PRED ITEM) is non-nil. +Once an ITEM is reached for which PRED returns nil, FN is no +longer called. Return nil; this function is intended for side +effects. + +Its anaphoric counterpart is `--each-r-while'." + (--each-r-while list (funcall pred it) (funcall fn it))) + +(defmacro --dotimes (num &rest body) + "Evaluate BODY NUM times, presumably for side effects. +BODY is evaluated with the local variable `it' temporarily bound +to successive integers running from 0, inclusive, to NUM, +exclusive. BODY is not evaluated if NUM is less than 1. +This is the anaphoric counterpart to `-dotimes'." + (declare (debug (form body)) (indent 1)) + (let ((n (make-symbol "num")) + (i (make-symbol "i"))) + `(let ((,n ,num) + (,i 0) + it) + (ignore it) + (while (< ,i ,n) + (setq it ,i ,i (1+ ,i)) + ,@body)))) + +(defun -dotimes (num fn) + "Call FN NUM times, presumably for side effects. +FN is called with a single argument on successive integers +running from 0, inclusive, to NUM, exclusive. FN is not called +if NUM is less than 1. + +This function's anaphoric counterpart is `--dotimes'." + (declare (indent 1)) + (--dotimes num (funcall fn it))) + +(defun -map (fn list) + "Apply FN to each item in LIST and return the list of results. + +This function's anaphoric counterpart is `--map'." + (declare (important-return-value t)) + (mapcar fn list)) + +(defmacro --map (form list) + "Eval FORM for each item in LIST and return the list of results. +Each element of LIST in turn is bound to `it' before evaluating +FORM. +This is the anaphoric counterpart to `-map'." + (declare (debug (def-form form))) + `(mapcar (lambda (it) (ignore it) ,form) ,list)) + +(defmacro --reduce-from (form init list) + "Accumulate a value by evaluating FORM across LIST. +This macro is like `--each' (which see), but it additionally +provides an accumulator variable `acc' which it successively +binds to the result of evaluating FORM for the current LIST +element before processing the next element. For the first +element, `acc' is initialized with the result of evaluating INIT. +The return value is the resulting value of `acc'. If LIST is +empty, FORM is not evaluated, and the return value is the result +of INIT. +This is the anaphoric counterpart to `-reduce-from'." + (declare (debug (form form form))) + `(let ((acc ,init)) + (--each ,list (setq acc ,form)) + acc)) + +(defun -reduce-from (fn init list) + "Reduce the function FN across LIST, starting with INIT. +Return the result of applying FN to INIT and the first element of +LIST, then applying FN to that result and the second element, +etc. If LIST is empty, return INIT without calling FN. + +This function's anaphoric counterpart is `--reduce-from'. + +For other folds, see also `-reduce' and `-reduce-r'." + (declare (important-return-value t)) + (--reduce-from (funcall fn acc it) init list)) + +(defmacro --reduce (form list) + "Accumulate a value by evaluating FORM across LIST. +This macro is like `--reduce-from' (which see), except the first +element of LIST is taken as INIT. Thus if LIST contains a single +item, it is returned without evaluating FORM. If LIST is empty, +FORM is evaluated with `it' and `acc' bound to nil. +This is the anaphoric counterpart to `-reduce'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reduce-from ,form (car ,lv) (cdr ,lv)) + ;; Explicit nil binding pacifies lexical "variable left uninitialized" + ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. + (let ((acc nil) (it nil)) + (ignore acc it) + ,form))))) + +(defun -reduce (fn list) + "Reduce the function FN across LIST. +Return the result of applying FN to the first two elements of +LIST, then applying FN to that result and the third element, etc. +If LIST contains a single element, return it without calling FN. +If LIST is empty, return the result of calling FN with no +arguments. + +This function's anaphoric counterpart is `--reduce'. + +For other folds, see also `-reduce-from' and `-reduce-r'." + (declare (important-return-value t)) + (if list + (-reduce-from fn (car list) (cdr list)) + (funcall fn))) + +(defmacro --reduce-r-from (form init list) + "Accumulate a value by evaluating FORM across LIST in reverse. +This macro is like `--reduce-from', except it starts from the end +of LIST. +This is the anaphoric counterpart to `-reduce-r-from'." + (declare (debug (form form form))) + `(let ((acc ,init)) + (--each-r ,list (setq acc ,form)) + acc)) + +(defun -reduce-r-from (fn init list) + "Reduce the function FN across LIST in reverse, starting with INIT. +Return the result of applying FN to the last element of LIST and +INIT, then applying FN to the second-to-last element and the +previous result of FN, etc. That is, the first argument of FN is +the current element, and its second argument the accumulated +value. If LIST is empty, return INIT without calling FN. + +This function is like `-reduce-from' but the operation associates +from the right rather than left. In other words, it starts from +the end of LIST and flips the arguments to FN. Conceptually, it +is like replacing the conses in LIST with applications of FN, and +its last link with INIT, and evaluating the resulting expression. + +This function's anaphoric counterpart is `--reduce-r-from'. + +For other folds, see also `-reduce-r' and `-reduce'." + (declare (important-return-value t)) + (--reduce-r-from (funcall fn it acc) init list)) + +(defmacro --reduce-r (form list) + "Accumulate a value by evaluating FORM across LIST in reverse order. +This macro is like `--reduce', except it starts from the end of +LIST. +This is the anaphoric counterpart to `-reduce-r'." + (declare (debug (form form))) + `(--reduce ,form (reverse ,list))) + +(defun -reduce-r (fn list) + "Reduce the function FN across LIST in reverse. +Return the result of applying FN to the last two elements of +LIST, then applying FN to the third-to-last element and the +previous result of FN, etc. That is, the first argument of FN is +the current element, and its second argument the accumulated +value. If LIST contains a single element, return it without +calling FN. If LIST is empty, return the result of calling FN +with no arguments. + +This function is like `-reduce' but the operation associates from +the right rather than left. In other words, it starts from the +end of LIST and flips the arguments to FN. Conceptually, it is +like replacing the conses in LIST with applications of FN, +ignoring its last link, and evaluating the resulting expression. + +This function's anaphoric counterpart is `--reduce-r'. + +For other folds, see also `-reduce-r-from' and `-reduce'." + (declare (important-return-value t)) + (if list + (--reduce-r (funcall fn it acc) list) + (funcall fn))) + +(defmacro --reductions-from (form init list) + "Return a list of FORM's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-from' (which see) is called with the same +arguments. +This is the anaphoric counterpart to `-reductions-from'." + (declare (debug (form form form))) + `(nreverse + (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list ,init) + ,list))) + +(defun -reductions-from (fn init list) + "Return a list of FN's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-from' (which see) is called with the same +arguments. + +This function's anaphoric counterpart is `--reductions-from'. + +For other folds, see also `-reductions' and `-reductions-r'." + (declare (important-return-value t)) + (--reductions-from (funcall fn acc it) init list)) + +(defmacro --reductions (form list) + "Return a list of FORM's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce' (which see) is called with the same arguments. +This is the anaphoric counterpart to `-reductions'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reductions-from ,form (car ,lv) (cdr ,lv)) + ;; Explicit nil binding pacifies lexical "variable left uninitialized" + ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. + (let ((acc nil) (it nil)) + (ignore acc it) + (list ,form)))))) + +(defun -reductions (fn list) + "Return a list of FN's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce' (which see) is called with the same arguments. + +This function's anaphoric counterpart is `--reductions'. + +For other folds, see also `-reductions' and `-reductions-r'." + (declare (important-return-value t)) + (if list + (--reductions-from (funcall fn acc it) (car list) (cdr list)) + (list (funcall fn)))) + +(defmacro --reductions-r-from (form init list) + "Return a list of FORM's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-r-from' (which see) is called with the same +arguments. +This is the anaphoric counterpart to `-reductions-r-from'." + (declare (debug (form form form))) + `(--reduce-r-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list ,init) + ,list)) + +(defun -reductions-r-from (fn init list) + "Return a list of FN's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-r-from' (which see) is called with the same +arguments. + +This function's anaphoric counterpart is `--reductions-r-from'. + +For other folds, see also `-reductions' and `-reductions-r'." + (declare (important-return-value t)) + (--reductions-r-from (funcall fn it acc) init list)) + +(defmacro --reductions-r (form list) + "Return a list of FORM's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-re' (which see) is called with the same arguments. +This is the anaphoric counterpart to `-reductions-r'." + (declare (debug (form list))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv (reverse ,list))) + (if ,lv + (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list (car ,lv)) + (cdr ,lv)) + ;; Explicit nil binding pacifies lexical "variable left uninitialized" + ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. + (let ((acc nil) (it nil)) + (ignore acc it) + (list ,form)))))) + +(defun -reductions-r (fn list) + "Return a list of FN's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-r' (which see) is called with the same arguments. + +This function's anaphoric counterpart is `--reductions-r'. + +For other folds, see also `-reductions-r-from' and +`-reductions'." + (declare (important-return-value t)) + (if list + (--reductions-r (funcall fn it acc) list) + (list (funcall fn)))) + +(defmacro --filter (form list) + "Return a new list of the items in LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-filter'. +For the opposite operation, see also `--remove'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (when ,form (push it ,r))) + (nreverse ,r)))) + +(defun -filter (pred list) + "Return a new list of the items in LIST for which PRED returns non-nil. + +Alias: `-select'. + +This function's anaphoric counterpart is `--filter'. + +For similar operations, see also `-keep' and `-remove'." + (declare (important-return-value t)) + (--filter (funcall pred it) list)) + +(defalias '-select '-filter) +(defalias '--select '--filter) + +(defmacro --remove (form list) + "Return a new list of the items in LIST for which FORM evals to nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-remove'. +For the opposite operation, 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'. + +This function's anaphoric counterpart is `--remove'. + +For similar operations, see also `-keep' and `-filter'." + (declare (important-return-value t)) + (--remove (funcall pred it) list)) + +(defalias '-reject '-remove) +(defalias '--reject '--remove) + +(defmacro --remove-first (form list) + "Remove the first item from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. This is a +non-destructive operation, but only the front of LIST leading up +to the removed item is a copy; the rest is LIST's original tail. +If no item is removed, then the result is a complete copy. +This is the anaphoric counterpart to `-remove-first'." + (declare (debug (form form))) + (let ((front (make-symbol "front")) + (tail (make-symbol "tail"))) + `(let ((,tail ,list) ,front) + (--each-while ,tail (not ,form) + (push (pop ,tail) ,front)) + (if ,tail + (nconc (nreverse ,front) (cdr ,tail)) + (nreverse ,front))))) + +(defun -remove-first (pred list) + "Remove the first item from LIST for which PRED returns non-nil. +This is a non-destructive operation, but only the front of LIST +leading up to the removed item is a copy; the rest is LIST's +original tail. If no item is removed, then the result is a +complete copy. + +Alias: `-reject-first'. + +This function's anaphoric counterpart is `--remove-first'. + +See also `-map-first', `-remove-item', and `-remove-last'." + (declare (important-return-value t)) + (--remove-first (funcall pred it) list)) + +;; TODO: #'-quoting the macro upsets Emacs 24. +(defalias '-reject-first #'-remove-first) +(defalias '--reject-first '--remove-first) + +(defmacro --remove-last (form list) + "Remove the last item from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' before evaluating +FORM. The result is a copy of LIST regardless of whether an +element is removed. +This is the anaphoric counterpart to `-remove-last'." + (declare (debug (form form))) + `(nreverse (--remove-first ,form (reverse ,list)))) + +(defun -remove-last (pred list) + "Remove the last item from LIST for which PRED returns non-nil. +The result is a copy of LIST regardless of whether an element is +removed. + +Alias: `-reject-last'. + +This function's anaphoric counterpart is `--remove-last'. + +See also `-map-last', `-remove-item', and `-remove-first'." + (declare (important-return-value t)) + (--remove-last (funcall pred it) list)) + +(defalias '-reject-last '-remove-last) +(defalias '--reject-last '--remove-last) + +(defalias '-remove-item #'remove + "Return a copy of LIST with all occurrences of ITEM removed. +The comparison is done with `equal'. +\n(fn ITEM LIST)") + +(defmacro --keep (form list) + "Eval FORM for each item in LIST and return the non-nil results. +Like `--filter', but returns the non-nil results of FORM instead +of the corresponding elements of LIST. Each element of LIST in +turn is bound to `it' and its index within LIST to `it-index' +before evaluating FORM. +This is the anaphoric counterpart to `-keep'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (m (make-symbol "mapped"))) + `(let (,r) + (--each ,list (let ((,m ,form)) (when ,m (push ,m ,r)))) + (nreverse ,r)))) + +(defun -keep (fn list) + "Return a new list of the non-nil results of applying FN to each item in LIST. +Like `-filter', but returns the non-nil results of FN instead of +the corresponding elements of LIST. + +Its anaphoric counterpart is `--keep'." + (declare (important-return-value t)) + (--keep (funcall fn it) list)) + +(defun -non-nil (list) + "Return a copy of LIST with all nil items removed." + (declare (side-effect-free t)) + (--filter it list)) + +(defmacro --map-indexed (form list) + "Eval FORM for each item in LIST and return the list of results. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. This is like +`--map', but additionally makes `it-index' available to FORM. + +This is the anaphoric counterpart to `-map-indexed'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list + (push ,form ,r)) + (nreverse ,r)))) + +(defun -map-indexed (fn list) + "Apply FN to each index and item in LIST and return the list of results. +This is like `-map', but FN takes two arguments: the index of the +current element within LIST, and the element itself. + +This function's anaphoric counterpart is `--map-indexed'. + +For a side-effecting variant, see also `-each-indexed'." + (declare (important-return-value t)) + (--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) + "Use PRED to conditionally apply REP to each item in LIST. +Return a copy of LIST where the items for which PRED returns nil +are unchanged, and the rest are mapped through the REP function. + +Alias: `-replace-where' + +See also: `-update-at'" + (declare (important-return-value t)) + (--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) + "Use PRED to determine the first item in LIST to call REP on. +Return a copy of LIST where the first item for which PRED returns +non-nil is replaced with the result of calling REP on that item. + +See also: `-map-when', `-replace-first'" + (declare (important-return-value t)) + (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'." + (declare (debug (def-form def-form form))) + `(-map-first (lambda (it) (ignore it) ,pred) + (lambda (it) (ignore it) ,rep) + ,list)) + +(defun -map-last (pred rep list) + "Use PRED to determine the last item in LIST to call REP on. +Return a copy of LIST where the last item for which PRED returns +non-nil is replaced with the result of calling REP on that item. + +See also: `-map-when', `-replace-last'" + (declare (important-return-value t)) + (nreverse (-map-first pred rep (reverse list)))) + +(defmacro --map-last (pred rep list) + "Anaphoric form of `-map-last'." + (declare (debug (def-form def-form form))) + `(-map-last (lambda (it) (ignore 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." + (declare (important-return-value t)) + (--mapcat (funcall fn it) list)) + +(defmacro --iterate (form init n) + "Anaphoric version of `-iterate'." + (declare (debug (form form form))) + (let ((res (make-symbol "result")) + (len (make-symbol "n"))) + `(let ((,len ,n)) + (when (> ,len 0) + (let* ((it ,init) + (,res (list it))) + (dotimes (_ (1- ,len)) + (push (setq it ,form) ,res)) + (nreverse ,res)))))) + +(defun -iterate (fun init n) + "Return a list of iterated applications of FUN to INIT. + +This means a list of the form: + + (INIT (FUN INIT) (FUN (FUN INIT)) ...) + +N is the length of the returned list." + (declare (important-return-value t)) + (--iterate (funcall fun it) init n)) + +(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))) + +(defun -flatten-n (num list) + "Flatten NUM levels of a nested LIST. + +See also: `-flatten'" + (declare (pure t) (side-effect-free t)) + (dotimes (_ num) + (setq list (apply #'append (mapcar #'-list list)))) + list) + +(defalias '-concat #'append + "Concatenate all the arguments and make the result a list. +The result is a list whose elements are the elements of all the arguments. +Each argument may be a list, vector or string. + +All arguments except the last argument are copied. The last argument +is just used as the tail of the new list. + +\(fn &rest SEQUENCES)") + +(defalias '-copy #'copy-sequence + "Create a shallow copy of LIST. + +\(fn LIST)") + +(defmacro --splice (pred form list) + "Splice lists generated by FORM in place of items satisfying PRED in LIST. + +Evaluate PRED for each element of LIST in turn bound to `it'. +Whenever the result of PRED is nil, leave that `it' is-is. +Otherwise, evaluate FORM with the same `it' binding still in +place. The result should be a (possibly empty) list of items to +splice in place of `it' in LIST. + +This can be useful as an alternative to the `,@' construct in a +`\\=`' structure, in case you need to splice several lists at +marked positions (for example with keywords). + +This is the anaphoric counterpart to `-splice'." + (declare (debug (form form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list + (if ,pred + (--each ,form (push it ,r)) + (push it ,r))) + (nreverse ,r)))) + +(defun -splice (pred fun list) + "Splice lists generated by FUN in place of items satisfying PRED in LIST. + +Call PRED on each element of LIST. Whenever the result of PRED +is nil, leave that `it' as-is. Otherwise, call FUN on the same +`it' that satisfied PRED. The result should be a (possibly +empty) list of items to splice in place of `it' in LIST. + +This can be useful as an alternative to the `,@' construct in a +`\\=`' structure, in case you need to splice several lists at +marked positions (for example with keywords). + +This function's anaphoric counterpart is `--splice'. + +See also: `-splice-list', `-insert-at'." + (declare (important-return-value t)) + (--splice (funcall pred it) (funcall fun it) list)) + +(defun -splice-list (pred new-list list) + "Splice NEW-LIST in place of elements matching PRED in LIST. + +See also: `-splice', `-insert-at'" + (declare (important-return-value t)) + (-splice pred (lambda (_) new-list) list)) + +(defmacro --splice-list (pred new-list list) + "Anaphoric form of `-splice-list'." + (declare (debug (def-form form form))) + `(-splice-list (lambda (it) (ignore it) ,pred) ,new-list ,list)) + +(defun -cons* (&rest args) + "Make a new list from the elements of ARGS. +The last 2 elements of ARGS are used as the final cons of the +result, so if the final element of ARGS is not a list, the result +is a dotted list. With no ARGS, return nil." + (declare (side-effect-free t)) + (let* ((len (length args)) + (tail (nthcdr (- len 2) args)) + (last (cdr tail))) + (if (null last) + (car args) + (setcdr tail (car last)) + 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 any ELEMENTS are given, append them to the list as well." + (declare (side-effect-free t)) + (-concat list (list elem) elements)) + +(defmacro --first (form list) + "Return the first item in LIST for which FORM evals to non-nil. +Return nil if no such element is found. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-first'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (or (not ,form) + (ignore (setq ,n it)))) + ,n))) + +(defun -first (pred list) + "Return the first item in LIST for which PRED returns non-nil. +Return nil if no such element is found. + +To get the first item in the list no questions asked, +use `-first-item'. + +Alias: `-find'. + +This function's anaphoric counterpart is `--first'." + (declare (important-return-value t)) + (--first (funcall pred it) list)) + +(defalias '-find #'-first) +(defalias '--find '--first) + +(defmacro --some (form list) + "Return non-nil if FORM evals to non-nil for at least one item in LIST. +If so, return the first such result of FORM. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-some'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not (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'. + +This function's anaphoric counterpart is `--some'." + (declare (important-return-value t)) + (--some (funcall pred it) list)) + +(defalias '-any '-some) +(defalias '--any '--some) + +(defmacro --every (form list) + "Return non-nil if FORM evals to non-nil for all items in LIST. +If so, return the last such result of FORM. Otherwise, once an +item is reached for which FORM yields nil, return nil without +evaluating FORM for any further LIST elements. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. + +This macro is like `--every-p', but on success returns the last +non-nil result of FORM instead of just t. + +This is the anaphoric counterpart to `-every'." + (declare (debug (form form))) + (let ((a (make-symbol "all"))) + `(let ((,a t)) + (--each-while ,list (setq ,a ,form)) + ,a))) + +(defun -every (pred list) + "Return non-nil if PRED returns non-nil for all items in LIST. +If so, return the last such result of PRED. Otherwise, once an +item is reached for which PRED returns nil, return nil without +calling PRED on any further LIST elements. + +This function is like `-every-p', but on success returns the last +non-nil result of PRED instead of just t. + +This function's anaphoric counterpart is `--every'." + (declare (important-return-value t)) + (--every (funcall pred it) list)) + +(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." + (declare (important-return-value t)) + (--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', etc. + +\(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) +(put '-first-item 'pure t) +(put '-first-item 'side-effect-free t) + +(defalias '-second-item #'cadr + "Return the second item of LIST, or nil if LIST is too short. + +See also: `-first-item', `-third-item', etc. + +\(fn LIST)") + +(put '-second-item 'pure t) +(put '-second-item 'side-effect-free t) + +(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: `-second-item', `-fourth-item', etc. + +\(fn LIST)") + +(put '-third-item 'pure t) +(put '-third-item 'side-effect-free t) + +(defalias '-fourth-item + (if (fboundp 'cadddr) + #'cadddr + (lambda (list) (cadr (cddr list)))) + "Return the fourth item of LIST, or nil if LIST is too short. + +See also: `-third-item', `-fifth-item', etc. + +\(fn LIST)") + +(put '-fourth-item 'pure t) +(put '-fourth-item 'side-effect-free t) + +(defun -fifth-item (list) + "Return the fifth item of LIST, or nil if LIST is too short. + +See also: `-fourth-item', `-last-item', etc." + (declare (pure t) (side-effect-free t)) + (car (cddr (cddr list)))) + +(defun -last-item (list) + "Return the last item of LIST, or nil on an empty list. + +See also: `-first-item', etc." + (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." + (declare (important-return-value t)) + (--count (funcall pred it) list)) + +(defun ---truthy? (obj) + "Return OBJ as a boolean value (t or nil)." + (declare (pure t) (side-effect-free error-free)) + (and obj t)) + +(defmacro --any? (form list) + "Anaphoric form of `-any?'." + (declare (debug (form form))) + `(and (--some ,form ,list) t)) + +(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'" + (declare (important-return-value t)) + (--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) + "Return t if FORM evals to non-nil for all items in LIST. +Otherwise, once an item is reached for which FORM yields nil, +return nil without evaluating FORM for any further LIST elements. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. + +The similar macro `--every' is more widely useful, since it +returns the last non-nil result of FORM instead of just t on +success. + +Alias: `--all-p', `--every-p', `--every?'. + +This is the anaphoric counterpart to `-all?'." + (declare (debug (form form))) + `(and (--every ,form ,list) t)) + +(defun -all? (pred list) + "Return t if (PRED X) is non-nil for all X in LIST, else nil. +In the latter case, stop after the first X for which (PRED X) is +nil, without calling PRED on any subsequent elements of LIST. + +The similar function `-every' is more widely useful, since it +returns the last non-nil result of PRED instead of just t on +success. + +Alias: `-all-p', `-every-p', `-every?'. + +This function's anaphoric counterpart is `--all?'." + (declare (important-return-value t)) + (--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'" + (declare (important-return-value t)) + (--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 different LIST items both satisfy and do not satisfy PRED. +That is, if PRED returns both nil for at least one item, and +non-nil for at least one other item in LIST. Return nil if all +items satisfy the predicate or none of them do. + +Alias: `-only-some-p'" + (declare (important-return-value t)) + (--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 (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))) + +(defmacro --take-while (form list) + "Take successive items from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. Return a new +list of the successive elements from the start of LIST for which +FORM evaluates to non-nil. +This is the anaphoric counterpart to `-take-while'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each-while ,list ,form (push it ,r)) + (nreverse ,r)))) + +(defun -take-while (pred list) + "Take successive items from LIST for which PRED returns non-nil. +PRED is a function of one argument. Return a new list of the +successive elements from the start of LIST for which PRED returns +non-nil. + +This function's anaphoric counterpart is `--take-while'. + +For another variant, see also `-drop-while'." + (declare (important-return-value t)) + (--take-while (funcall pred it) list)) + +(defmacro --drop-while (form list) + "Drop successive items from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. Return the +tail (not a copy) of LIST starting from its first element for +which FORM evaluates to nil. +This is the anaphoric counterpart to `-drop-while'." + (declare (debug (form form))) + (let ((l (make-symbol "list"))) + `(let ((,l ,list)) + (--each-while ,l ,form (pop ,l)) + ,l))) + +(defun -drop-while (pred list) + "Drop successive items from LIST for which PRED returns non-nil. +PRED is a function of one argument. Return the tail (not a copy) +of LIST starting from its first element for which PRED returns +nil. + +This function's anaphoric counterpart is `--drop-while'. + +For another variant, see also `-take-while'." + (declare (important-return-value t)) + (--drop-while (funcall pred it) list)) + +(defun -take (n list) + "Return a copy of the first N items in LIST. +Return a copy of LIST if it contains N items or fewer. +Return nil if N is zero or less. + +See also: `-take-last'." + (declare (side-effect-free t)) + (--take-while (< it-index n) list)) + +(defun -take-last (n list) + "Return a copy of the last N items of LIST in order. +Return a copy of LIST if it contains N items or fewer. +Return nil if N is zero or less. + +See also: `-take'." + (declare (side-effect-free t)) + (copy-sequence (last list n))) + +(defalias '-drop #'nthcdr + "Return the tail (not a copy) of LIST without the first N items. +Return nil if LIST contains N items or fewer. +Return LIST if N is zero or less. + +For another variant, see also `-drop-last'. +\n(fn N LIST)") + +(defun -drop-last (n list) + "Return a copy of LIST without its last N items. +Return a copy of LIST if N is zero or less. +Return nil if LIST contains N items or fewer. + +See also: `-drop'." + (declare (side-effect-free t)) + (nbutlast (copy-sequence list) n)) + +(defun -split-at (n list) + "Split LIST into two sublists after the Nth element. +The result is a list of two elements (TAKE DROP) where TAKE is a +new list of the first N elements of LIST, and DROP is the +remaining elements of LIST (not a copy). TAKE and DROP are like +the results of `-take' and `-drop', respectively, but the split +is done in a single list traversal." + (declare (side-effect-free t)) + (let (result) + (--each-while list (< it-index n) + (push (pop list) result)) + (list (nreverse result) list))) + +(defun -rotate (n list) + "Rotate LIST N places to the right (left if N is negative). +The time complexity is O(n)." + (declare (pure t) (side-effect-free t)) + (cond ((null list) ()) + ((zerop n) (copy-sequence list)) + ((let* ((len (length list)) + (n-mod-len (mod n len)) + (new-tail-len (- len n-mod-len))) + (append (nthcdr 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) + "Use FUNC to update the Nth element of LIST. +Return a copy of LIST where the Nth element is replaced with the +result of calling FUNC on it. + +See also: `-map-when'" + (declare (important-return-value t)) + (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 def-form form))) + `(-update-at ,n (lambda (it) (ignore it) ,form) ,list)) + +(defun -remove-at (n list) + "Return LIST with its element at index N removed. +That is, remove any element selected as (nth N LIST) from LIST +and return the result. + +This is a non-destructive operation: parts of LIST (but not +necessarily all of it) are copied as needed to avoid +destructively modifying it. + +See also: `-remove-at-indices', `-remove'." + (declare (pure t) (side-effect-free t)) + (if (zerop n) + (cdr list) + (--remove-first (= it-index n) list))) + +(defun -remove-at-indices (indices list) + "Return LIST with its elements at INDICES removed. +That is, for each index I in INDICES, remove any element selected +as (nth I LIST) from LIST. + +This is a non-destructive operation: parts of LIST (but not +necessarily all of it) are copied as needed to avoid +destructively modifying it. + +See also: `-remove-at', `-remove'." + (declare (pure t) (side-effect-free t)) + (setq indices (--drop-while (< it 0) (-sort #'< indices))) + (let ((i (pop indices)) res) + (--each-while list i + (pop list) + (if (/= it-index i) + (push it res) + (while (and indices (= (car indices) i)) + (pop indices)) + (setq i (pop indices)))) + (nconc (nreverse res) list))) + +(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) + "Split LIST into a prefix satisfying PRED, and the rest. +The first sublist is the prefix of LIST with successive elements +satisfying PRED, and the second sublist is the remaining elements +that do not. The result is like performing + + ((-take-while PRED LIST) (-drop-while PRED LIST)) + +but in no more than a single pass through LIST." + (declare (important-return-value t)) + (--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 (def-form form))) + `(-split-when (lambda (it) (equal it ,item)) ,list)) + +(defmacro --split-when (form list) + "Anaphoric version of `-split-when'." + (declare (debug (def-form form))) + `(-split-when (lambda (it) (ignore 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'." + (declare (important-return-value t)) + (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) + "Split LIST into two sublists based on whether items satisfy PRED. +The result is like performing + + ((-filter PRED LIST) (-remove PRED LIST)) + +but in a single pass through LIST." + (declare (important-return-value t)) + (--separate (funcall pred it) list)) + +(defun dash--partition-all-in-steps-reversed (n step list) + "Like `-partition-all-in-steps', but the result is reversed." + (when (< step 1) + (signal 'wrong-type-argument + `("Step size < 1 results in juicy infinite loops" ,step))) + (let (result) + (while list + (push (-take n list) result) + (setq list (nthcdr step list))) + result)) + +(defun -partition-all-in-steps (n step list) + "Partition LIST into sublists of length N that are STEP items apart. +Adjacent groups may overlap if N exceeds the STEP stride. +Trailing groups may contain less than N items." + (declare (pure t) (side-effect-free t)) + (nreverse (dash--partition-all-in-steps-reversed n step list))) + +(defun -partition-in-steps (n step list) + "Partition LIST into sublists of length N that are STEP items apart. +Like `-partition-all-in-steps', but 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 (dash--partition-all-in-steps-reversed n step list))) + (while (and result (< (length (car result)) n)) + (pop 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." + (declare (important-return-value t)) + (--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)." + (declare (important-return-value t)) + (--partition-by-header (funcall fn it) list)) + +(defmacro --partition-after-pred (form list) + "Partition LIST after each element for which FORM evaluates to non-nil. +Each element of LIST in turn is bound to `it' before evaluating +FORM. + +This is the anaphoric counterpart to `-partition-after-pred'." + (let ((l (make-symbol "list")) + (r (make-symbol "result")) + (s (make-symbol "sublist"))) + `(let ((,l ,list) ,r ,s) + (when ,l + (--each ,l + (push it ,s) + (when ,form + (push (nreverse ,s) ,r) + (setq ,s ()))) + (when ,s + (push (nreverse ,s) ,r)) + (nreverse ,r))))) + +(defun -partition-after-pred (pred list) + "Partition LIST after each element for which PRED returns non-nil. + +This function's anaphoric counterpart is `--partition-after-pred'." + (declare (important-return-value t)) + (--partition-after-pred (funcall pred it) list)) + +(defun -partition-before-pred (pred list) + "Partition directly before each time PRED is true on an element of LIST." + (declare (important-return-value t)) + (nreverse (-map #'reverse + (-partition-after-pred pred (reverse list))))) + +(defun -partition-after-item (item list) + "Partition directly after each time ITEM appears in LIST." + (declare (pure t) (side-effect-free t)) + (-partition-after-pred (lambda (ele) (equal ele item)) + list)) + +(defun -partition-before-item (item list) + "Partition directly before each time ITEM appears in LIST." + (declare (pure t) (side-effect-free t)) + (-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'." + (declare (important-return-value t)) + (--group-by (funcall fn it) list)) + +(defun -interpose (sep list) + "Return a new list of all elements in LIST separated by SEP." + (declare (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 (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) + "Zip LIST1 and LIST2 into a new list according to FORM. +That is, evaluate FORM for each item pair from the two lists, and +return the list of results. The result is as long as the shorter +list. + +Each element of LIST1 and each element of LIST2 in turn are bound +pairwise to `it' and `other', respectively, and their index +within the list to `it-index', before evaluating FORM. + +This is the anaphoric counterpart to `-zip-with'." + (declare (debug (form form form))) + (let ((r (make-symbol "result")) + (l2 (make-symbol "list2"))) + `(let ((,l2 ,list2) ,r) + (--each-while ,list1 ,l2 + (let ((other (pop ,l2))) + (ignore other) + (push ,form ,r))) + (nreverse ,r)))) + +(defun -zip-with (fn list1 list2) + "Zip LIST1 and LIST2 into a new list using the function FN. +That is, apply FN pairwise taking as first argument the next +element of LIST1 and as second argument the next element of LIST2 +at the corresponding position. The result is as long as the +shorter list. + +This function's anaphoric counterpart is `--zip-with'. + +For other zips, see also `-zip-lists' and `-zip-fill'." + (declare (important-return-value t)) + (--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 element of +each list, and so on. The number of returned groupings is equal +to the length of the shortest input list, and the length of each +grouping is equal to the number of input LISTS. + +The return value is always a list of proper lists, in contrast to +`-zip' which returns a list of dotted pairs when only two input +LISTS are provided. + +See also: `-zip-pair'." + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (--every it lists) + (push (mapcar #'car lists) results) + (setq lists (mapcar #'cdr lists))) + (nreverse results)))) + +(defun -zip-lists-fill (fill-value &rest lists) + "Zip LISTS together, padding shorter lists with FILL-VALUE. +This is like `-zip-lists' (which see), except it retains all +elements at positions beyond the end of the shortest list. The +number of returned groupings is equal to the length of the +longest input list, and the length of each grouping is equal to +the number of input LISTS." + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (--some it lists) + (push (--map (if it (car it) fill-value) lists) results) + (setq lists (mapcar #'cdr lists))) + (nreverse results)))) + +(defun -unzip-lists (lists) + "Unzip LISTS. + +This works just like `-zip-lists' (which see), but takes a list +of lists instead of a variable number of arguments, such that + + (-unzip-lists (-zip-lists ARGS...)) + +is identity (given that the lists comprising ARGS are of the same +length)." + (declare (pure t) (side-effect-free t)) + (apply #'-zip-lists lists)) + +(defalias 'dash--length= + (if (fboundp 'length=) + #'length= + (lambda (list length) + (cond ((< length 0) nil) + ((zerop length) (null list)) + ((let ((last (nthcdr (1- length) list))) + (and last (null (cdr last)))))))) + "Return non-nil if LIST is of LENGTH. +This is a compatibility shim for `length=' in Emacs 28. +\n(fn LIST LENGTH)") + +(defun dash--zip-lists-or-pair (_form &rest lists) + "Return a form equivalent to applying `-zip' to LISTS. +This `compiler-macro' warns about discouraged `-zip' usage and +delegates to `-zip-lists' or `-zip-pair' depending on the number +of LISTS." + (if (not (dash--length= lists 2)) + (cons #'-zip-lists lists) + (let ((pair (cons #'-zip-pair lists)) + (msg "Use -zip-pair instead of -zip to get a list of pairs")) + (if (fboundp 'macroexp-warn-and-return) + (macroexp-warn-and-return msg pair) + (message msg) + pair)))) + +(defun -zip (&rest lists) + "Zip LISTS together. + +Group the head of each list, followed by the second element of +each list, and so on. The number of returned groupings is equal +to the length of the shortest input list, and the number of items +in each grouping is equal to the number of input LISTS. + +If only two LISTS are provided as arguments, return the groupings +as a list of dotted pairs. Otherwise, return the groupings as a +list of proper lists. + +Since the return value changes form depending on the number of +arguments, it is generally recommended to use `-zip-lists' +instead, or `-zip-pair' if a list of dotted pairs is desired. + +See also: `-unzip'." + (declare (compiler-macro dash--zip-lists-or-pair) + (pure t) (side-effect-free t)) + ;; For backward compatibility, return a list of dotted pairs if two + ;; arguments were provided. + (apply (if (dash--length= lists 2) #'-zip-pair #'-zip-lists) lists)) + +(defun -zip-pair (&rest lists) + "Zip LIST1 and LIST2 together. + +Make a pair with the head of each list, followed by a pair with +the second element of each list, and so on. The number of pairs +returned is equal to the length of the shorter input list. + +See also: `-zip-lists'." + (declare (advertised-calling-convention (list1 list2) "2.20.0") + (pure t) (side-effect-free t)) + (if (dash--length= lists 2) + (--zip-with (cons it other) (car lists) (cadr lists)) + (apply #'-zip-lists lists))) + +(defun -zip-fill (fill-value &rest lists) + "Zip LISTS together, padding shorter lists with FILL-VALUE. +This is like `-zip' (which see), except it retains all elements +at positions beyond the end of the shortest list. The number of +returned groupings is equal to the length of the longest input +list, and the length of each grouping is equal to the number of +input LISTS. + +Since the return value changes form depending on the number of +arguments, it is generally recommended to use `-zip-lists-fill' +instead, unless a list of dotted pairs is explicitly desired." + (declare (pure t) (side-effect-free t)) + (cond ((null lists) ()) + ((dash--length= lists 2) + (let ((list1 (car lists)) + (list2 (cadr lists)) + results) + (while (or list1 list2) + (push (cons (if list1 (pop list1) fill-value) + (if list2 (pop list2) fill-value)) + results)) + (nreverse results))) + ((apply #'-zip-lists-fill fill-value lists)))) + +(defun -unzip (lists) + "Unzip LISTS. + +This works just like `-zip' (which see), 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 of the same length, and +that `-zip' is not called with two arguments, because of the +caveat described in its docstring). + +Note in particular that calling `-unzip' on a list of two lists +will return a list of dotted pairs. + +Since the return value changes form depending on the number of +LISTS, it is generally recommended to use `-unzip-lists' instead." + (declare (pure t) (side-effect-free t)) + (apply #'-zip lists)) + +(defun -cycle (list) + "Return an infinite circular copy of LIST. +The returned list cycles through the elements of LIST and repeats +from the beginning." + (declare (pure t) (side-effect-free t)) + ;; Also works with sequences that aren't lists. + (let ((newlist (append list ()))) + (nconc newlist newlist))) + +(defun -pad (fill-value &rest lists) + "Pad each of LISTS with FILL-VALUE until they all have equal lengths. + +Ensure all LISTS are as long as the longest one by repeatedly +appending FILL-VALUE to the shorter lists, and return the +resulting LISTS." + (declare (pure t) (side-effect-free t)) + (let* ((lens (mapcar #'length lists)) + (maxlen (apply #'max 0 lens))) + (--map (append it (make-list (- maxlen (pop lens)) fill-value)) lists))) + +(defmacro --annotate (form list) + "Pair each item in LIST with the result of evaluating FORM. + +Return an alist of (RESULT . ITEM), where each ITEM is the +corresponding element of LIST, and RESULT is the value obtained +by evaluating FORM with ITEM bound to `it'. + +This is the anaphoric counterpart to `-annotate'." + (declare (debug (form form))) + `(--map (cons ,form it) ,list)) + +(defun -annotate (fn list) + "Pair each item in LIST with the result of passing it to FN. + +Return an alist of (RESULT . ITEM), where each ITEM is the +corresponding element of LIST, and RESULT is the value obtained +by calling FN on ITEM. + +This function's anaphoric counterpart is `--annotate'." + (declare (important-return-value t)) + (--annotate (funcall fn it) 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'" + (declare (important-return-value t)) + (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'" + (declare (important-return-value t)) + (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))) + +(defmacro --find-index (form list) + "Return the first index in LIST for which FORM evals to non-nil. +Return nil if no such index is found. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-find-index'." + (declare (debug (form form))) + `(--some (and ,form it-index) ,list)) + +(defun -find-index (pred list) + "Return the index of the first item satisfying PRED in LIST. +Return nil if no such item is found. + +PRED is called with one argument, the current list element, until +it returns non-nil, at which point the search terminates. + +This function's anaphoric counterpart is `--find-index'. + +See also: `-first', `-find-last-index'." + (declare (important-return-value t)) + (--find-index (funcall pred it) list)) + +(defun -elem-index (elem list) + "Return the first index of ELEM in LIST. +That is, the index within LIST of the first element that is +`equal' to ELEM. Return nil if there is no such element. + +See also: `-find-index'." + (declare (pure t) (side-effect-free t)) + (--find-index (equal elem it) list)) + +(defmacro --find-indices (form list) + "Return the list of indices in LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-find-indices'." + (declare (debug (form form))) + `(--keep (and ,form it-index) ,list)) + +(defun -find-indices (pred list) + "Return the list of indices in LIST satisfying PRED. + +Each element of LIST in turn is passed to PRED. If the result is +non-nil, the index of that element in LIST is included in the +result. The returned indices are in ascending order, i.e., in +the same order as they appear in LIST. + +This function's anaphoric counterpart is `--find-indices'. + +See also: `-find-index', `-elem-indices'." + (declare (important-return-value t)) + (--find-indices (funcall pred it) list)) + +(defun -elem-indices (elem list) + "Return the list of indices at which ELEM appears in LIST. +That is, the indices of all elements of LIST `equal' to ELEM, in +the same ascending order as they appear in LIST." + (declare (pure t) (side-effect-free t)) + (--find-indices (equal elem it) list)) + +(defmacro --find-last-index (form list) + "Return the last index in LIST for which FORM evals to non-nil. +Return nil if no such index is found. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-find-last-index'." + (declare (debug (form form))) + (let ((i (make-symbol "index"))) + `(let (,i) + (--each ,list + (when ,form (setq ,i it-index))) + ,i))) + +(defun -find-last-index (pred list) + "Return the index of the last item satisfying PRED in LIST. +Return nil if no such item is found. + +Predicate PRED is called with one argument each time, namely the +current list element. + +This function's anaphoric counterpart is `--find-last-index'. + +See also: `-last', `-find-index'." + (declare (important-return-value t)) + (--find-last-index (funcall pred it) 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 the 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--> (expr &rest forms) + "Thread EXPR through FORMS via `-->', while the result is non-nil. +When EXPR evaluates to non-nil, thread the result through the +first of FORMS, and when that result is non-nil, thread it +through the next form, etc." + (declare (debug (form &rest &or symbolp consp)) (indent 1)) + (if (null forms) expr + (let ((result (make-symbol "result"))) + `(-some--> (-when-let (,result ,expr) + (--> ,result ,(car forms))) + ,@(cdr forms))))) + +(defmacro -doto (init &rest forms) + "Evaluate INIT and pass it as argument to FORMS with `->'. +The RESULT of evaluating INIT is threaded through each of FORMS +individually using `->', which see. The return value is RESULT, +which FORMS may have modified by side effect." + (declare (debug (form &rest &or symbolp consp)) (indent 1)) + (let ((retval (make-symbol "result"))) + `(let ((,retval ,init)) + ,@(mapcar (lambda (form) `(-> ,retval ,form)) forms) + ,retval))) + +(defmacro --doto (init &rest forms) + "Anaphoric form of `-doto'. +This just evaluates INIT, binds the result to `it', evaluates +FORMS, and returns the final value of `it'. +Note: `it' need not be used in each form." + (declare (debug (form body)) (indent 1)) + `(let ((it ,init)) + ,@forms + it)) + +(defun -grade-up (comparator list) + "Grade elements of LIST using COMPARATOR relation. +This yields a permutation vector such that applying this +permutation to LIST sorts it in ascending order." + (declare (important-return-value t)) + (->> (--map-indexed (cons it it-index) list) + (-sort (lambda (it other) (funcall comparator (car it) (car other)))) + (mapcar #'cdr))) + +(defun -grade-down (comparator list) + "Grade elements of LIST using COMPARATOR relation. +This yields a permutation vector such that applying this +permutation to LIST sorts it in descending order." + (declare (important-return-value t)) + (->> (--map-indexed (cons it it-index) list) + (-sort (lambda (it other) (funcall comparator (car other) (car it)))) + (mapcar #'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--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)) + `(substring ,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 (-zip-fill 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 + ((and (symbolp match-form) + ;; Don't bind things like &keys as if they were vars (#395). + (not (functionp (dash--get-expand-function 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 (substring 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 (--zip-with (list (car it) (car other)) + 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 a description of the destructuring mechanism." + (declare (doc-string 2) (indent defun) + (debug (&define sexp + [&optional stringp] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((nlistp match-form) + (signal 'wrong-type-argument (list #'listp match-form))) + ;; No destructuring, so just return regular `lambda' for speed. + ((-all? #'symbolp match-form) + `(lambda ,match-form ,@body)) + ((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 create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(lambda ,(mapcar #'cadr 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) + (signal 'wrong-number-of-arguments (list '-setq (1+ (length forms))))) + (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))) + +;; TODO: Get rid of this dynamic variable, passing it as an argument +;; instead? +(defvar -compare-fn nil + "Tests for equality use this function, or `equal' if this is nil. + +As a dynamic variable, this should be temporarily bound around +the relevant operation, rather than permanently modified. For +example: + + (let ((-compare-fn #\\='=)) + (-union \\='(1 2 3) \\='(2 3 4)))") + +(defun dash--member-fn () + "Return the flavor of `member' that goes best with `-compare-fn'." + (declare (side-effect-free error-free)) + (let ((cmp -compare-fn)) + (cond ((memq cmp '(nil equal)) #'member) + ((eq cmp #'eq) #'memq) + ((eq cmp #'eql) #'memql) + ((lambda (elt list) + (while (and list (not (funcall cmp elt (car list)))) + (pop list)) + list))))) + +(defun dash--assoc-fn () + "Return the flavor of `assoc' that goes best with `-compare-fn'." + (declare (side-effect-free error-free)) + (let ((cmp -compare-fn)) + (cond ((memq cmp '(nil equal)) #'assoc) + ((eq cmp #'eq) #'assq) + ;; Since Emacs 26, `assoc' accepts a custom `testfn'. + ;; Version testing would be simpler here, but feature + ;; testing gets more brownie points, I guess. + ((condition-case nil + (with-no-warnings (assoc nil () #'eql)) + (wrong-number-of-arguments t)) + (lambda (key alist) + (--first (and (consp it) (funcall cmp (car it) key)) alist))) + ((with-no-warnings + (lambda (key alist) + (assoc key alist cmp))))))) + +(defun dash--hash-test-fn () + "Return the hash table test function corresponding to `-compare-fn'. +Return nil if `-compare-fn' is not a known test function." + (declare (side-effect-free error-free)) + ;; In theory this could also recognize values that are custom + ;; `hash-table-test's, but too often the :test name is different + ;; from the equality function, so it doesn't seem worthwhile. + (car (memq (or -compare-fn #'equal) '(equal eq eql)))) + +(defvar dash--short-list-length 32 + "Maximum list length considered short, for optimizations. +For example, the speedup afforded by hash table lookup may start +to outweigh its runtime and memory overhead for problem sizes +greater than this value. See also the discussion in PR #305.") + +(defun -distinct (list) + "Return a copy of LIST with all duplicate elements removed. + +The test for equality is done with `equal', or with `-compare-fn' +if that is non-nil. + +Alias: `-uniq'." + (declare (important-return-value t)) + (let (test len) + (cond ((null list) ()) + ;; Use a hash table if `-compare-fn' is a known hash table + ;; test function and the list is long enough. + ((and (setq test (dash--hash-test-fn)) + (> (setq len (length list)) dash--short-list-length)) + (let ((ht (make-hash-table :test test :size len))) + (--filter (unless (gethash it ht) (puthash it t ht)) list))) + ((let ((member (dash--member-fn)) uniq) + (--each list (unless (funcall member it uniq) (push it uniq))) + (nreverse uniq)))))) + +(defalias '-uniq #'-distinct) + +(defun dash--size+ (size1 size2) + "Return the sum of nonnegative fixnums SIZE1 and SIZE2. +Return `most-positive-fixnum' on overflow. This ensures the +result is a valid size, particularly for allocating hash tables, +even in the presence of bignum support." + (declare (side-effect-free t)) + (if (< size1 (- most-positive-fixnum size2)) + (+ size1 size2) + most-positive-fixnum)) + +(defun -union (list1 list2) + "Return a new list of distinct elements appearing in either LIST1 or LIST2. + +The test for equality is done with `equal', or with `-compare-fn' +if that is non-nil." + (declare (important-return-value t)) + (let ((lists (list list1 list2)) test len union) + (cond ((null (or list1 list2))) + ;; Use a hash table if `-compare-fn' is a known hash table + ;; test function and the lists are long enough. + ((and (setq test (dash--hash-test-fn)) + (> (setq len (dash--size+ (length list1) (length list2))) + dash--short-list-length)) + (let ((ht (make-hash-table :test test :size len))) + (dolist (l lists) + (--each l (unless (gethash it ht) + (puthash it t ht) + (push it union)))))) + ((let ((member (dash--member-fn))) + (dolist (l lists) + (--each l (unless (funcall member it union) (push it union))))))) + (nreverse union))) + +(defun -intersection (list1 list2) + "Return a new list of distinct elements appearing in both LIST1 and LIST2. + +The test for equality is done with `equal', or with `-compare-fn' +if that is non-nil." + (declare (important-return-value t)) + (let (test len) + (cond ((null (and list1 list2)) ()) + ;; Use a hash table if `-compare-fn' is a known hash table + ;; test function and either list is long enough. + ((and (setq test (dash--hash-test-fn)) + (> (setq len (length list2)) dash--short-list-length)) + (let ((ht (make-hash-table :test test :size len))) + (--each list2 (puthash it t ht)) + ;; Remove visited elements to avoid duplicates. + (--filter (when (gethash it ht) (remhash it ht) t) list1))) + ((let ((member (dash--member-fn)) intersection) + (--each list1 (and (funcall member it list2) + (not (funcall member it intersection)) + (push it intersection))) + (nreverse intersection)))))) + +(defun -difference (list1 list2) + "Return a new list with the distinct members of LIST1 that are not in LIST2. + +The test for equality is done with `equal', or with `-compare-fn' +if that is non-nil." + (declare (important-return-value t)) + (let (test len1 len2) + (cond ((null list1) ()) + ((null list2) (-distinct list1)) + ;; Use a hash table if `-compare-fn' is a known hash table + ;; test function and the subtrahend is long enough. + ((and (setq test (dash--hash-test-fn)) + (setq len1 (length list1)) + (setq len2 (length list2)) + (> (max len1 len2) dash--short-list-length)) + (let ((ht1 (make-hash-table :test test :size len1)) + (ht2 (make-hash-table :test test :size len2))) + (--each list2 (puthash it t ht2)) + ;; Avoid duplicates by tracking visited items in `ht1'. + (--filter (unless (or (gethash it ht2) (gethash it ht1)) + (puthash it t ht1)) + list1))) + ((let ((member (dash--member-fn)) difference) + (--each list1 + (unless (or (funcall member it list2) + (funcall member it difference)) + (push it difference))) + (nreverse difference)))))) + +(defun -powerset (list) + "Return the power set of LIST." + (declare (pure t) (side-effect-free t)) + (if (null list) (list ()) + (let ((last (-powerset (cdr list)))) + (nconc (mapcar (lambda (x) (cons (car list) x)) last) + last)))) + +(defun -frequencies (list) + "Count the occurrences of each distinct element of LIST. + +Return an alist of (ELEMENT . N), where each ELEMENT occurs N +times in LIST. + +The test for equality is done with `equal', or with `-compare-fn' +if that is non-nil. + +See also `-count' and `-group-by'." + (declare (important-return-value t)) + (let (test len freqs) + (cond ((null list)) + ((and (setq test (dash--hash-test-fn)) + (> (setq len (length list)) dash--short-list-length)) + (let ((ht (make-hash-table :test test :size len))) + ;; Share structure between hash table and returned list. + ;; This affords a single pass that preserves the input + ;; order, conses less garbage, and is faster than a + ;; second traversal (e.g., with `maphash'). + (--each list + (let ((freq (gethash it ht))) + (if freq + (setcdr freq (1+ (cdr freq))) + (push (puthash it (cons it 1) ht) freqs)))))) + ((let ((assoc (dash--assoc-fn))) + (--each list + (let ((freq (funcall assoc it freqs))) + (if freq + (setcdr freq (1+ (cdr freq))) + (push (cons it 1) freqs))))))) + (nreverse freqs))) + +(defun dash--numbers<= (nums) + "Return non-nil if NUMS is a list of non-decreasing numbers." + (declare (pure t) (side-effect-free t)) + (or (null nums) + (let ((prev (pop nums))) + (and (numberp prev) + (--every (and (numberp it) (<= prev (setq prev it))) nums))))) + +(defun dash--next-lex-perm (array n) + "Update ARRAY of N numbers with its next lexicographic permutation. +Return nil if there is no such successor. N should be nonzero. + +This implements the salient steps of Algorithm L (Lexicographic +permutation generation) as described in DE Knuth's The Art of +Computer Programming, Volume 4A / Combinatorial Algorithms, +Part I, Addison-Wesley, 2011, § 7.2.1.2, p. 319." + (setq n (1- n)) + (let* ((l n) + (j (1- n)) + (al (aref array n)) + (aj al)) + ;; L2. [Find j]. + ;; Decrement j until a[j] < a[j+1]. + (while (and (<= 0 j) + (<= aj (setq aj (aref array j)))) + (setq j (1- j))) + ;; Terminate algorithm if j not found. + (when (>= j 0) + ;; L3. [Increase a[j]]. + ;; Decrement l until a[j] < a[l]. + (while (>= aj al) + (setq l (1- l) al (aref array l))) + ;; Swap a[j] and a[l]. + (aset array j al) + (aset array l aj) + ;; L4. [Reverse a[j+1]...a[n]]. + (setq l n) + (while (< (setq j (1+ j)) l) + (setq aj (aref array j)) + (aset array j (aref array l)) + (aset array l aj) + (setq l (1- l))) + array))) + +(defun dash--lex-perms (vec &optional original) + "Return a list of permutations of VEC in lexicographic order. +Specifically, return only the successors of VEC in lexicographic +order. Each returned permutation is a list. VEC should comprise +one or more numbers, and may be destructively modified. + +If ORIGINAL is a vector, then VEC is interpreted as a set of +indices into ORIGINAL. In this case, the indices are permuted, +and the resulting index permutations are used to dereference +elements of ORIGINAL." + (let ((len (length vec)) perms) + (while vec + (push (if original + (--map (aref original it) vec) + (append vec ())) + perms) + (setq vec (dash--next-lex-perm vec len))) + (nreverse perms))) + +(defun dash--uniq-perms (list) + "Return a list of permutations of LIST. +LIST is treated as if all its elements are distinct." + (let* ((vec (vconcat list)) + (idxs (copy-sequence vec))) + ;; Just construct a vector of the list's indices and permute that. + (dotimes (i (length idxs)) + (aset idxs i i)) + (dash--lex-perms idxs vec))) + +(defun dash--multi-perms (list freqs) + "Return a list of permutations of the multiset LIST. +FREQS should be an alist describing the frequency of each element +in LIST, as returned by `-frequencies'." + (let (;; Distinct items in `list', aka the cars of `freqs'. + (uniq (make-vector (length freqs) nil)) + ;; Indices into `uniq'. + (idxs (make-vector (length list) nil)) + ;; Current index into `idxs'. + (i 0)) + (--each freqs + (aset uniq it-index (car it)) + ;; Populate `idxs' with as many copies of each `it-index' as + ;; there are corresponding duplicates. + (dotimes (_ (cdr it)) + (aset idxs i it-index) + (setq i (1+ i)))) + (dash--lex-perms idxs uniq))) + +(defun -permutations (list) + "Return the distinct permutations of LIST. + +Duplicate elements of LIST are determined by `equal', or by +`-compare-fn' if that is non-nil." + (declare (important-return-value t)) + (cond ((null list) (list ())) + ;; Optimization: a traversal of `list' is faster than the + ;; round trip via `dash--uniq-perms' or `dash--multi-perms'. + ((dash--numbers<= list) + (dash--lex-perms (vconcat list))) + ((let ((freqs (-frequencies list))) + ;; Is each element distinct? + (unless (--every (= (cdr it) 1) freqs) + (dash--multi-perms list freqs)))) + ((dash--uniq-perms list)))) + +(defun -inits (list) + "Return all prefixes of LIST." + (declare (pure t) (side-effect-free t)) + (let ((res (list list))) + (setq list (reverse list)) + (while list + (push (reverse (!cdr list)) res)) + res)) + +(defun -tails (list) + "Return all suffixes of LIST." + (declare (pure t) (side-effect-free t)) + (-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." + (declare (pure t) (side-effect-free t)) + (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 is non-nil. As with `member', the return value is +actually the tail of LIST whose car is ELEMENT. + +Alias: `-contains-p'." + (declare (important-return-value t)) + (funcall (dash--member-fn) element list)) + +(defalias '-contains-p #'-contains?) + +(defun -same-items? (list1 list2) + "Return non-nil if LIST1 and LIST2 have the same distinct elements. + +The order of the elements in the lists does not matter. The +lists may be of different lengths, i.e., contain duplicate +elements. The test for equality is done with `equal', or with +`-compare-fn' if that is non-nil. + +Alias: `-same-items-p'." + (declare (important-return-value t)) + (let (test len1 len2) + (cond ((null (or list1 list2))) + ((null (and list1 list2)) nil) + ;; Use a hash table if `-compare-fn' is a known hash table + ;; test function and either list is long enough. + ((and (setq test (dash--hash-test-fn)) + (setq len1 (length list1)) + (setq len2 (length list2)) + (> (max len1 len2) dash--short-list-length)) + (let ((ht1 (make-hash-table :test test :size len1)) + (ht2 (make-hash-table :test test :size len2))) + (--each list1 (puthash it t ht1)) + ;; Move visited elements from `ht1' to `ht2'. This way, + ;; if visiting all of `list2' leaves `ht1' empty, then + ;; all elements from both lists have been accounted for. + (and (--every (cond ((gethash it ht1) + (remhash it ht1) + (puthash it t ht2)) + ((gethash it ht2))) + list2) + (zerop (hash-table-count ht1))))) + ((let ((member (dash--member-fn))) + (and (--all? (funcall member it list2) list1) + (--all? (funcall member it list1) list2))))))) + +(defalias '-same-items-p #'-same-items?) + +(defun -is-prefix? (prefix list) + "Return non-nil if PREFIX is a prefix of LIST. + +Alias: `-is-prefix-p'." + (declare (pure t) (side-effect-free t)) + (--each-while list (and (equal (car prefix) it) + (!cdr prefix))) + (null prefix)) + +(defun -is-suffix? (suffix list) + "Return non-nil if SUFFIX is a suffix of LIST. + +Alias: `-is-suffix-p'." + (declare (pure t) (side-effect-free t)) + (equal suffix (last list (length suffix)))) + +(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." + (declare (important-return-value t)) + ;; Not yet worth changing to (sort list :lessp comparator); + ;; still seems as fast or slightly faster. + (sort (copy-sequence list) comparator)) + +(defmacro --sort (form list) + "Anaphoric form of `-sort'." + (declare (debug (def-form form))) + `(-sort (lambda (it other) (ignore it other) ,form) ,list)) + +(defun -list (&optional arg &rest args) + "Ensure ARG is a list. +If ARG is already a list, return it as is (not a copy). +Otherwise, return a new list with ARG as its only element. + +Another supported calling convention is (-list &rest ARGS). +In this case, if ARG is not a list, a new list with all of +ARGS as elements is returned. This use is supported for +backward compatibility and is otherwise deprecated." + (declare (advertised-calling-convention (arg) "2.18.0") + (pure t) (side-effect-free error-free)) + (if (listp arg) arg (cons arg args))) + +(defun -repeat (n x) + "Return a new list of length N with each element being X. +Return nil if N is less than 1." + (declare (side-effect-free t)) + (and (>= n 0) (make-list n x))) + +(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)) + (or list (signal 'wrong-type-argument (list #'consp list))) + (-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)) + (or list (signal 'wrong-type-argument (list #'consp list))) + (-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." + (declare (important-return-value t)) + (--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." + (declare (important-return-value t)) + (--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 (def-form form))) + `(-max-by (lambda (it other) (ignore 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 (def-form form))) + `(-min-by (lambda (it other) (ignore it other) ,form) ,list)) + +(defun -iota (count &optional start step) + "Return a list containing COUNT numbers. +Starts from START and adds STEP each time. The default START is +zero, the default STEP is 1. +This function takes its name from the corresponding primitive in +the APL language." + (declare (side-effect-free t)) + (unless (natnump count) + (signal 'wrong-type-argument (list #'natnump count))) + (or start (setq start 0)) + (or step (setq step 1)) + (if (zerop step) + (make-list count start) + (--iterate (+ it step) start count))) + +(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'." + (declare (important-return-value t)) + (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'." + (declare (debug (def-form form))) + `(-fix (lambda (it) (ignore 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." + (declare (important-return-value t)) + (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 (def-form form))) + `(-unfold (lambda (it) (ignore it) ,form) ,seed)) + +(defun -cons-pair? (obj) + "Return non-nil if OBJ is a true cons pair. +That is, a cons (A . B) where B is not a list. + +Alias: `-cons-pair-p'." + (declare (pure t) (side-effect-free error-free)) + (nlistp (cdr-safe obj))) + +(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)) + (if (-cons-pair? val) (-cons-to-list val) (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." + (declare (important-return-value t)) + (cond + ((null tree) ()) + ((-cons-pair? tree) (funcall fn tree)) + ((consp tree) + (-reduce-r-from + folder init-value + (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree))) + ((funcall fn tree)))) + +(defmacro --tree-mapreduce-from (form folder init-value tree) + "Anaphoric form of `-tree-mapreduce-from'." + (declare (debug (def-form def-form form form))) + `(-tree-mapreduce-from (lambda (it) (ignore it) ,form) + (lambda (it acc) (ignore 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." + (declare (important-return-value t)) + (cond + ((null tree) ()) + ((-cons-pair? tree) (funcall fn tree)) + ((consp tree) + (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree))) + ((funcall fn tree)))) + +(defmacro --tree-mapreduce (form folder tree) + "Anaphoric form of `-tree-mapreduce'." + (declare (debug (def-form def-form form))) + `(-tree-mapreduce (lambda (it) (ignore it) ,form) + (lambda (it acc) (ignore it acc) ,folder) + ,tree)) + +(defun -tree-map (fn tree) + "Apply FN to each element of TREE while preserving the tree structure." + (declare (important-return-value t)) + (cond + ((null tree) ()) + ((-cons-pair? tree) (funcall fn tree)) + ((consp tree) + (mapcar (lambda (x) (-tree-map fn x)) tree)) + ((funcall fn tree)))) + +(defmacro --tree-map (form tree) + "Anaphoric form of `-tree-map'." + (declare (debug (def-form form))) + `(-tree-map (lambda (it) (ignore 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." + (declare (important-return-value t)) + (cond + ((null tree) ()) + ((-cons-pair? tree) tree) + ((consp tree) + (-reduce-r-from + fn init-value + (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree))) + (tree))) + +(defmacro --tree-reduce-from (form init-value tree) + "Anaphoric form of `-tree-reduce-from'." + (declare (debug (def-form form form))) + `(-tree-reduce-from (lambda (it acc) (ignore 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." + (declare (important-return-value t)) + (cond + ((null tree) ()) + ((-cons-pair? tree) tree) + ((consp tree) + (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree))) + (tree))) + +(defmacro --tree-reduce (form tree) + "Anaphoric form of `-tree-reduce'." + (declare (debug (def-form form))) + `(-tree-reduce (lambda (it acc) (ignore 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." + (cond ((funcall pred tree) (funcall fun tree)) + ((and (listp tree) (listp (cdr 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'." + (declare (debug (def-form def-form form))) + `(-tree-map-nodes (lambda (it) (ignore it) ,pred) + (lambda (it) (ignore 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." + (declare (important-return-value t)) + (cons tree + (and (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'." + (declare (debug (def-form def-form form))) + `(-tree-seq (lambda (it) (ignore it) ,branch) + (lambda (it) (ignore 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 (side-effect-free t)) + (-tree-map #'identity list)) + +;;; Combinators + +(defalias '-partial #'apply-partially) + +(defun -rpartial (fn &rest args) + "Return a function that is a partial application of FN to ARGS. +ARGS is a list of the last N arguments to pass to FN. The result +is a new function which does the same as FN, except that the last +N arguments are fixed at the values with which this function was +called. This is like `-partial', except the arguments are fixed +starting from the right rather than the left." + (declare (pure t) (side-effect-free error-free)) + (lambda (&rest args-before) (apply fn (append args-before args)))) + +(defun -juxt (&rest fns) + "Return a function that is the juxtaposition of FNS. +The returned function takes a variable number of ARGS, applies +each of FNS in turn to ARGS, and returns the list of results." + (declare (pure t) (side-effect-free error-free)) + (lambda (&rest args) (mapcar (lambda (x) (apply x args)) fns))) + +(defun -compose (&rest fns) + "Compose FNS into a single composite function. +Return a function that takes a variable number of ARGS, applies +the last function in FNS to ARGS, and returns the result of +calling each remaining function on the result of the previous +function, right-to-left. If no FNS are given, return a variadic +`identity' function." + (declare (pure t) (side-effect-free error-free)) + (let* ((fns (nreverse fns)) + (head (car fns)) + (tail (cdr fns))) + (cond (tail + (lambda (&rest args) + (--reduce-from (funcall it acc) (apply head args) tail))) + (fns head) + ((lambda (&optional arg &rest _) arg))))) + +(defun -applify (fn) + "Return a function that applies FN to a single list of args. +This changes the arity of FN from taking N distinct arguments to +taking 1 argument which is a list of N arguments." + (declare (pure t) (side-effect-free error-free)) + (lambda (args) (apply fn args))) + +(defun -on (op trans) + "Return a function that calls TRANS on each arg and OP on the results. +The returned function takes a variable number of arguments, calls +the function TRANS on each one in turn, and then passes those +results as the list of arguments to OP, in the same order. + +For example, the following pairs of expressions are morally +equivalent: + + (funcall (-on #\\='+ #\\='1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3)) + (funcall (-on #\\='+ #\\='1+)) = (+)" + (declare (pure t) (side-effect-free error-free)) + (lambda (&rest args) + ;; This unrolling seems to be a relatively cheap way to keep the + ;; overhead of `mapcar' + `apply' in check. + (cond ((cddr args) + (apply op (mapcar trans args))) + ((cdr args) + (funcall op (funcall trans (car args)) (funcall trans (cadr args)))) + (args + (funcall op (funcall trans (car args)))) + ((funcall op))))) + +(defun -flip (fn) + "Return a function that calls FN with its arguments reversed. +The returned function takes the same number of arguments as FN. + +For example, the following two expressions are morally +equivalent: + + (funcall (-flip #\\='-) 1 2) = (- 2 1) + +See also: `-rotate-args'." + (declare (pure t) (side-effect-free error-free)) + (lambda (&rest args) ;; Open-code for speed. + (cond ((cddr args) (apply fn (nreverse args))) + ((cdr args) (funcall fn (cadr args) (car args))) + (args (funcall fn (car args))) + ((funcall fn))))) + +(defun -rotate-args (n fn) + "Return a function that calls FN with args rotated N places to the right. +The returned function takes the same number of arguments as FN, +rotates the list of arguments N places to the right (left if N is +negative) just like `-rotate', and applies FN to the result. + +See also: `-flip'." + (declare (pure t) (side-effect-free t)) + (if (zerop n) + fn + (let ((even (= (% n 2) 0))) + (lambda (&rest args) + (cond ((cddr args) ;; Open-code for speed. + (apply fn (-rotate n args))) + ((cdr args) + (let ((fst (car args)) + (snd (cadr args))) + (funcall fn (if even fst snd) (if even snd fst)))) + (args + (funcall fn (car args))) + ((funcall fn))))))) + +(defun -const (c) + "Return a function that returns C ignoring any additional arguments. + +In types: a -> b -> a" + (declare (pure t) (side-effect-free error-free)) + (lambda (&rest _) c)) + +(defmacro -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." + (declare (debug (&optional sexp &rest &or "<>" form))) + (let* ((i 0) + (args (--keep (when (eq it '<>) + (setq i (1+ i)) + (make-symbol (format "D%d" i))) + params))) + `(lambda ,args + ,(let ((body (--map (if (eq it '<>) (pop args) it) params))) + (if (eq (car params) '<>) + (cons #'funcall body) + body))))) + +(defun -not (pred) + "Return a predicate that negates the result of PRED. +The returned predicate passes its arguments to PRED. If PRED +returns nil, the result is non-nil; otherwise the result is nil. + +See also: `-andfn' and `-orfn'." + (declare (pure t) (side-effect-free error-free)) + (lambda (&rest args) (not (apply pred args)))) + +(defun -orfn (&rest preds) + "Return a predicate that returns the first non-nil result of PREDS. +The returned predicate takes a variable number of arguments, +passes them to each predicate in PREDS in turn until one of them +returns non-nil, and returns that non-nil result without calling +the remaining PREDS. If all PREDS return nil, or if no PREDS are +given, the returned predicate returns nil. + +See also: `-andfn' and `-not'." + (declare (pure t) (side-effect-free error-free)) + ;; Open-code for speed. + (cond ((cdr preds) (lambda (&rest args) (--some (apply it args) preds))) + (preds (car preds)) + (#'ignore))) + +(defun -andfn (&rest preds) + "Return a predicate that returns non-nil if all PREDS do so. +The returned predicate P takes a variable number of arguments and +passes them to each predicate in PREDS in turn. If any one of +PREDS returns nil, P also returns nil without calling the +remaining PREDS. If all PREDS return non-nil, P returns the last +such value. If no PREDS are given, P always returns non-nil. + +See also: `-orfn' and `-not'." + (declare (pure t) (side-effect-free error-free)) + ;; Open-code for speed. + (cond ((cdr preds) (lambda (&rest args) (--every (apply it args) preds))) + (preds (car preds)) + ;; As a `pure' function, this runtime check may generate + ;; backward-incompatible bytecode for `(-andfn)' at compile-time, + ;; but I doubt that's a problem in practice (famous last words). + ((fboundp 'always) #'always) + ((lambda (&rest _) t)))) + +(defun -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' 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)))." + (declare (pure t) (side-effect-free error-free)) + (lambda (x) (--dotimes n (setq x (funcall fn x))) x)) + +(defun -counter (&optional beg end inc) + "Return a closure that counts from BEG to END, with increment INC. + +The closure will return the next value in the counting sequence +each time it is called, and nil after END is reached. BEG +defaults to 0, INC defaults to 1, and if END is nil, the counter +will increment indefinitely. + +The closure accepts any number of arguments, which are discarded." + (declare (pure t) (side-effect-free error-free)) + (let ((inc (or inc 1)) + (n (or beg 0))) + (lambda (&rest _) + (when (or (not end) (< n end)) + (prog1 n + (setq n (+ n inc))))))) + +(defvar -fixfn-max-iterations 1000 + "The default maximum number of iterations performed by `-fixfn' + unless otherwise specified.") + +(defun -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." + (declare (important-return-value t)) + (let ((eqfn (or equal-test 'equal)) + (haltfn (or halt-test + (-not + (-counter 0 -fixfn-max-iterations))))) + (lambda (x) + (let ((re (funcall fn x)) + (halt? (funcall haltfn x))) + (while (and (not halt?) (not (funcall eqfn x re))) + (setq x re + re (funcall fn re) + halt? (funcall haltfn re))) + (if halt? (cons 'halted halt?) + re))))) + +(defun -prodfn (&rest fns) + "Return a function that applies each of FNS to each of a list of arguments. + +Takes a list of N functions and returns a function that takes a +list of length N, applying Ith function to Ith 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))" + (declare (pure t) (side-effect-free t)) + (lambda (x) (--zip-with (funcall it other) fns x))) + +;;; Font lock + +(defvar dash--keywords + `(;; TODO: Do not fontify the following automatic variables + ;; globally; detect and limit to their local anaphoric scope. + (,(rx symbol-start (| "acc" "it" "it-index" "other") symbol-end) + 0 font-lock-variable-name-face) + ;; Macros in dev/examples.el. Based on `lisp-mode-symbol-regexp'. + (,(rx ?\( (group (| "defexamples" "def-example-group")) symbol-end + (+ (in "\t ")) + (group (* (| (syntax word) (syntax symbol) (: ?\\ nonl))))) + (1 font-lock-keyword-face) + (2 font-lock-function-name-face)) + ;; Symbols in dev/examples.el. + ,(rx symbol-start (| "=>" "~>" "!!>") symbol-end) + ;; Elisp macro fontification was static prior to Emacs 25. + ,@(when (< emacs-major-version 25) + (let ((macs '("!cdr" + "!cons" + "-->" + "--all-p" + "--all?" + "--annotate" + "--any" + "--any-p" + "--any?" + "--count" + "--dotimes" + "--doto" + "--drop-while" + "--each" + "--each-indexed" + "--each-r" + "--each-r-while" + "--each-while" + "--every" + "--every-p" + "--every?" + "--filter" + "--find" + "--find-index" + "--find-indices" + "--find-last-index" + "--first" + "--fix" + "--group-by" + "--if-let" + "--iterate" + "--keep" + "--last" + "--map" + "--map-first" + "--map-indexed" + "--map-last" + "--map-when" + "--mapcat" + "--max-by" + "--min-by" + "--none-p" + "--none?" + "--only-some-p" + "--only-some?" + "--partition-after-pred" + "--partition-by" + "--partition-by-header" + "--reduce" + "--reduce-from" + "--reduce-r" + "--reduce-r-from" + "--reductions" + "--reductions-from" + "--reductions-r" + "--reductions-r-from" + "--reject" + "--reject-first" + "--reject-last" + "--remove" + "--remove-first" + "--remove-last" + "--replace-where" + "--select" + "--separate" + "--some" + "--some-p" + "--some?" + "--sort" + "--splice" + "--splice-list" + "--split-when" + "--split-with" + "--take-while" + "--tree-map" + "--tree-map-nodes" + "--tree-mapreduce" + "--tree-mapreduce-from" + "--tree-reduce" + "--tree-reduce-from" + "--tree-seq" + "--unfold" + "--update-at" + "--when-let" + "--zip-with" + "->" + "->>" + "-as->" + "-cut" + "-doto" + "-if-let" + "-if-let*" + "-lambda" + "-let" + "-let*" + "-setq" + "-some-->" + "-some->" + "-some->>" + "-split-on" + "-when-let" + "-when-let*"))) + `((,(concat "(" (regexp-opt macs 'symbols)) . 1))))) + "Font lock keywords for `dash-fontify-mode'.") + +(defcustom dash-fontify-mode-lighter nil + "Mode line lighter for `dash-fontify-mode'. +Either a string to display in the mode line when +`dash-fontify-mode' is on, or nil to display +nothing (the default)." + :package-version '(dash . "2.18.0") + :type '(choice (string :tag "Lighter" :value " Dash") + (const :tag "Nothing" nil))) + +;;;###autoload +(define-minor-mode dash-fontify-mode + "Toggle fontification of Dash special variables. + +Dash-Fontify mode is a buffer-local minor mode intended for Emacs +Lisp buffers. Enabling it causes the special variables bound in +anaphoric Dash macros to be fontified. These anaphoras include +`it', `it-index', `acc', and `other'. In older Emacs versions +which do not dynamically detect macros, Dash-Fontify mode +additionally fontifies Dash macro calls. + +See also `dash-fontify-mode-lighter' and +`global-dash-fontify-mode'." + :lighter dash-fontify-mode-lighter + (if dash-fontify-mode + (font-lock-add-keywords nil dash--keywords t) + (font-lock-remove-keywords nil dash--keywords)) + (cond ((fboundp 'font-lock-flush) ;; Added in Emacs 25. + (font-lock-flush)) + ;; `font-lock-fontify-buffer' unconditionally enables + ;; `font-lock-mode' and is marked `interactive-only' in later + ;; Emacs versions which have `font-lock-flush', so we guard + ;; and pacify as needed, respectively. + (font-lock-mode + (with-no-warnings + (font-lock-fontify-buffer))))) + +(defun dash--turn-on-fontify-mode () + "Enable `dash-fontify-mode' if in an Emacs Lisp buffer." + (when (derived-mode-p #'emacs-lisp-mode) + (dash-fontify-mode))) + +;;;###autoload +(define-globalized-minor-mode global-dash-fontify-mode + dash-fontify-mode dash--turn-on-fontify-mode) + +(defcustom dash-enable-fontlock nil + "If non-nil, fontify Dash macro calls and special variables." + :set (lambda (sym val) + (set-default sym val) + (global-dash-fontify-mode (if val 1 0))) + :type 'boolean) + +(make-obsolete-variable + 'dash-enable-fontlock #'global-dash-fontify-mode "2.18.0") + +(define-obsolete-function-alias + 'dash-enable-font-lock #'global-dash-fontify-mode "2.18.0") + +;;; Info + +(defvar dash--info-doc-spec '("(dash) Index" nil "^ -+ .*: " "\\( \\|$\\)") + "The Dash :doc-spec entry for `info-lookup-alist'. +It is based on that for `emacs-lisp-mode'.") + +(defun dash--info-elisp-docs () + "Return the `emacs-lisp-mode' symbol docs from `info-lookup-alist'. +Specifically, return the cons containing their +`info-lookup->doc-spec' so that we can modify it." + (defvar info-lookup-alist) + (nthcdr 3 (assq #'emacs-lisp-mode (cdr (assq 'symbol info-lookup-alist))))) + +;;;###autoload +(defun dash-register-info-lookup () + "Register the Dash Info manual with `info-lookup-symbol'. +This allows Dash symbols to be looked up with \\[info-lookup-symbol]." + (interactive) + (require 'info-look) + (let ((docs (dash--info-elisp-docs))) + (setcar docs (append (car docs) (list dash--info-doc-spec))) + (info-lookup-reset))) + +(defun dash-unload-function () + "Remove Dash from `info-lookup-alist'. +Used by `unload-feature', which see." + (let ((docs (and (featurep 'info-look) + (dash--info-elisp-docs)))) + (when (member dash--info-doc-spec (car docs)) + (setcar docs (remove dash--info-doc-spec (car docs))) + (info-lookup-reset))) + nil) + +(provide 'dash) +;;; dash.el ends here diff --git a/elpa/dash-20240510.1327/dash.info b/elpa/dash-20240510.1327/dash.info new file mode 100644 index 00000000..4a660217 --- /dev/null +++ b/elpa/dash-20240510.1327/dash.info @@ -0,0 +1,4948 @@ +This is dash.info, produced by makeinfo version 6.7 from dash.texi. + +This manual is for Dash version 2.19.1. + + Copyright © 2012–2024 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with the Invariant Sections being “GNU General Public + License,” and no Front-Cover Texts or Back-Cover Texts. A copy of + the license is included in the section entitled “GNU Free + Documentation License”. +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 version 2.19.1. + + Copyright © 2012–2024 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with the Invariant Sections being “GNU General Public + License,” and no Front-Cover Texts or Back-Cover Texts. A copy of + the license is included in the section entitled “GNU Free + Documentation License”. + +* Menu: + +* Installation:: Installing and configuring Dash. +* Functions:: Dash API reference. +* Development:: Contributing to Dash development. + +Appendices + +* FDL:: The license for this documentation. +* GPL:: Conditions for copying and changing Dash. +* Index:: Index including functions and macros. + + — The Detailed Node Listing — + +Installation + +* Using in a package:: Listing Dash as a package dependency. +* Fontification of special variables:: Font Lock of anaphoric macro variables. +* Info symbol lookup:: Looking up Dash symbols in this manual. + +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. +* Contributors:: List of contributors. + + +File: dash.info, Node: Installation, Next: Functions, Prev: Top, Up: Top + +1 Installation +************** + +Dash is available on GNU ELPA (https://elpa.gnu.org/), GNU-devel ELPA +(https://elpa.gnu.org/devel/), and MELPA (https://melpa.org/), and can +be installed with the standard command ‘package-install’ (*note +(emacs)Package Installation::). + +‘M-x package-install dash ’ + Install the Dash library. + + Alternatively, you can just dump ‘dash.el’ in your ‘load-path’ +somewhere (*note (emacs)Lisp Libraries::). + +* Menu: + +* Using in a package:: Listing Dash as a package dependency. +* Fontification of special variables:: Font Lock of anaphoric macro variables. +* Info symbol lookup:: Looking up Dash symbols in this manual. + + +File: dash.info, Node: Using in a package, Next: Fontification of special variables, Up: Installation + +1.1 Using in a package +====================== + +If you use Dash in your own package, be sure to list it as a dependency +in the library’s headers as follows (*note (elisp)Library Headers::). + + ;; Package-Requires: ((dash "2.19.1")) + + +File: dash.info, Node: Fontification of special variables, Next: Info symbol lookup, Prev: Using in a package, Up: Installation + +1.2 Fontification of special variables +====================================== + +The autoloaded minor mode ‘dash-fontify-mode’ is provided for optional +fontification of anaphoric Dash variables (‘it’, ‘acc’, etc.) in Emacs +Lisp buffers using search-based Font Lock (*note (emacs)Font Lock::). +In older Emacs versions which do not dynamically detect macros, the +minor mode also fontifies calls to Dash macros. + + To automatically enable the minor mode in all Emacs Lisp buffers, +just call its autoloaded global counterpart ‘global-dash-fontify-mode’, +either interactively or from your ‘user-init-file’: + + (global-dash-fontify-mode) + + +File: dash.info, Node: Info symbol lookup, Prev: Fontification of special variables, Up: Installation + +1.3 Info symbol lookup +====================== + +While editing Elisp files, you can use ‘C-h S’ (‘info-lookup-symbol’) to +look up Elisp symbols in the relevant Info manuals (*note (emacs)Info +Lookup::). To enable the same for Dash symbols, use the command +‘dash-register-info-lookup’. It can be called directly when needed, or +automatically from your ‘user-init-file’. For example: + + (with-eval-after-load 'info-look + (dash-register-info-lookup)) + + +File: dash.info, Node: Functions, Next: Development, Prev: Installation, Up: Top + +2 Functions +*********** + +This chapter contains reference documentation for the Dash API +(Application Programming Interface). The names of all public functions +defined in the library are prefixed with a dash character (‘-’). + + The library also provides anaphoric macro versions of functions where +that makes sense. The names of these macros are prefixed with two +dashes (‘--’) instead of one. + + For instance, while the function ‘-map’ applies a function to each +element of a list, its anaphoric counterpart ‘--map’ evaluates a form +with the local variable ‘it’ temporarily bound to the current list +element instead. + + ;; Normal version. + (-map (lambda (n) (* n n)) '(1 2 3 4)) + ⇒ (1 4 9 16) + + ;; Anaphoric version. + (--map (* it it) '(1 2 3 4)) + ⇒ (1 4 9 16) + + The normal version can, of course, also be written as in the +following example, which demonstrates the utility of both versions. + + (defun my-square (n) + "Return N multiplied by itself." + (* n n)) + + (-map #'my-square '(1 2 3 4)) + ⇒ (1 4 9 16) + +* 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 a new list. + + -- Function: -map (fn list) + Apply FN to each item in LIST and return the list of results. + + This function’s anaphoric counterpart is ‘--map’. + + (-map (lambda (num) (* num num)) '(1 2 3 4)) + ⇒ (1 4 9 16) + (-map #'1+ '(1 2 3 4)) + ⇒ (2 3 4 5) + (--map (* it it) '(1 2 3 4)) + ⇒ (1 4 9 16) + + -- Function: -map-when (pred rep list) + Use PRED to conditionally apply REP to each item in LIST. Return a + copy of LIST where the items for which PRED returns ‘nil’ are + unchanged, and the rest 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) + Use PRED to determine the first item in LIST to call REP on. + Return a copy of LIST where the first item for which PRED returns + non-‘nil’ is replaced with the result of calling REP on that 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) + Use PRED to determine the last item in LIST to call REP on. Return + a copy of LIST where the last item for which PRED returns non-‘nil’ + is replaced with the result of calling REP on that 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) + Apply FN to each index and item in LIST and return the list of + results. This is like ‘-map’ (*note -map::), but FN takes two + arguments: the index of the current element within LIST, and the + element itself. + + This function’s anaphoric counterpart is ‘--map-indexed’. + + For a side-effecting variant, 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) + (-map-indexed #'* '(1 2 3 4)) + ⇒ (0 2 6 12) + + -- Function: -annotate (fn list) + Pair each item in LIST with the result of passing it to FN. + + Return an alist of (RESULT . ITEM), where each ITEM is the + corresponding element of LIST, and RESULT is the value obtained by + calling FN on ITEM. + + This function’s anaphoric counterpart is ‘--annotate’. + + (-annotate #'1+ '(1 2 3)) + ⇒ ((2 . 1) (3 . 2) (4 . 3)) + (-annotate #'length '((f o o) (bar baz))) + ⇒ ((3 f o o) (2 bar baz)) + (--annotate (> it 1) '(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 items satisfying PRED in + LIST. + + Call PRED on each element of LIST. Whenever the result of PRED is + ‘nil’, leave that ‘it’ as-is. Otherwise, call FUN on the same ‘it’ + that satisfied PRED. The result should be a (possibly empty) list + of items to splice in place of ‘it’ in LIST. + + This can be useful as an alternative to the ‘,@’ construct in a ‘`’ + structure, in case you need to splice several lists at marked + positions (for example with keywords). + + This function’s anaphoric counterpart is ‘--splice’. + + See also: ‘-splice-list’ (*note -splice-list::), ‘-insert-at’ + (*note -insert-at::). + + (-splice #'numberp (lambda (n) (list n n)) '(a 1 b 2)) + ⇒ (a 1 1 b 2 2) + (--splice t (list it it) '(1 2 3 4)) + ⇒ (1 1 2 2 3 3 4 4) + (--splice (eq it :magic) '((magical) (code)) '((foo) :magic (bar))) + ⇒ ((foo) (magical) (code) (bar)) + + -- 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 (list) + Create a shallow copy of 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 + non-‘nil’. + + Alias: ‘-select’. + + This function’s anaphoric counterpart is ‘--filter’. + + For similar operations, see also ‘-keep’ (*note -keep::) and + ‘-remove’ (*note -remove::). + + (-filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) + ⇒ (2 4) + (-filter #'natnump '(-2 -1 0 1 2)) + ⇒ (0 1 2) + (--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’. + + This function’s anaphoric counterpart is ‘--remove’. + + For similar operations, see also ‘-keep’ (*note -keep::) and + ‘-filter’ (*note -filter::). + + (-remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) + ⇒ (1 3) + (-remove #'natnump '(-2 -1 0 1 2)) + ⇒ (-2 -1) + (--remove (= 0 (% it 2)) '(1 2 3 4)) + ⇒ (1 3) + + -- Function: -remove-first (pred list) + Remove the first item from LIST for which PRED returns non-‘nil’. + This is a non-destructive operation, but only the front of LIST + leading up to the removed item is a copy; the rest is LIST’s + original tail. If no item is removed, then the result is a + complete copy. + + Alias: ‘-reject-first’. + + This function’s anaphoric counterpart is ‘--remove-first’. + + See also ‘-map-first’ (*note -map-first::), ‘-remove-item’ (*note + -remove-item::), and ‘-remove-last’ (*note -remove-last::). + + (-remove-first #'natnump '(-2 -1 0 1 2)) + ⇒ (-2 -1 1 2) + (-remove-first #'stringp '(1 2 "first" "second")) + ⇒ (1 2 "second") + (--remove-first (> it 3) '(1 2 3 4 5 6)) + ⇒ (1 2 3 5 6) + + -- Function: -remove-last (pred list) + Remove the last item from LIST for which PRED returns non-‘nil’. + The result is a copy of LIST regardless of whether an element is + removed. + + Alias: ‘-reject-last’. + + This function’s anaphoric counterpart is ‘--remove-last’. + + See also ‘-map-last’ (*note -map-last::), ‘-remove-item’ (*note + -remove-item::), and ‘-remove-first’ (*note -remove-first::). + + (-remove-last #'natnump '(1 3 5 4 7 8 10 -11)) + ⇒ (1 3 5 4 7 8 -11) + (-remove-last #'stringp '(1 2 "last" "second")) + ⇒ (1 2 "last") + (--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) + Return a copy of LIST with all occurrences of ITEM removed. The + 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")) + ⇒ ("alice" "eve") + + -- Function: -non-nil (list) + Return a copy of LIST with all ‘nil’ items removed. + + (-non-nil '(nil 1 nil 2 nil nil 3 4 nil 5 nil)) + ⇒ (1 2 3 4 5) + (-non-nil '((nil))) + ⇒ ((nil)) + (-non-nil ()) + ⇒ () + + -- 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 copy of the first N items in LIST. Return a copy of LIST + if it contains N items or fewer. Return ‘nil’ if N is zero or + less. + + 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) + (-take 0 '(1 2 3 4 5)) + ⇒ () + + -- Function: -take-last (n list) + Return a copy of the last N items of LIST in order. Return a copy + of LIST if it contains N items or fewer. Return ‘nil’ if N is zero + or less. + + 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 (not a copy) of LIST without the first N items. + Return ‘nil’ if LIST contains N items or fewer. Return LIST if N + is zero or less. + + For another variant, see also ‘-drop-last’ (*note -drop-last::). + + (-drop 3 '(1 2 3 4 5)) + ⇒ (4 5) + (-drop 17 '(1 2 3 4 5)) + ⇒ () + (-drop 0 '(1 2 3 4 5)) + ⇒ (1 2 3 4 5) + + -- Function: -drop-last (n list) + Return a copy of LIST without its last N items. Return a copy of + LIST if N is zero or less. Return ‘nil’ if LIST contains N items + or fewer. + + See also: ‘-drop’ (*note -drop::). + + (-drop-last 3 '(1 2 3 4 5)) + ⇒ (1 2) + (-drop-last 17 '(1 2 3 4 5)) + ⇒ () + (-drop-last 0 '(1 2 3 4 5)) + ⇒ (1 2 3 4 5) + + -- Function: -take-while (pred list) + Take successive items from LIST for which PRED returns non-‘nil’. + PRED is a function of one argument. Return a new list of the + successive elements from the start of LIST for which PRED returns + non-‘nil’. + + This function’s anaphoric counterpart is ‘--take-while’. + + For another variant, see also ‘-drop-while’ (*note -drop-while::). + + (-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) + Drop successive items from LIST for which PRED returns non-‘nil’. + PRED is a function of one argument. Return the tail (not a copy) + of LIST starting from its first element for which PRED returns + ‘nil’. + + This function’s anaphoric counterpart is ‘--drop-while’. + + For another variant, see also ‘-take-while’ (*note -take-while::). + + (-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 each + item in LIST. Like ‘-filter’ (*note -filter::), but returns the + non-‘nil’ results of FN instead of the corresponding elements of + LIST. + + Its anaphoric counterpart is ‘--keep’. + + (-keep #'cdr '((1 2 3) (4 5) (6))) + ⇒ ((2 3) (5)) + (-keep (lambda (n) (and (> n 3) (* 10 n))) '(1 2 3 4 5 6)) + ⇒ (40 50 60) + (--keep (and (> it 3) (* 10 it)) '(1 2 3 4 5 6)) + ⇒ (40 50 60) + + -- Function: -concat (&rest sequences) + Concatenate all the arguments and make the result a list. The + result is a list whose elements are the elements of all the + arguments. Each argument may be a list, vector or string. + + All arguments except the last argument are copied. The last + argument is just used as the tail of the new list. + + (-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) + Use FUNC to update the Nth element of LIST. Return a copy of LIST + where the Nth element is replaced with the result of calling FUNC + on it. + + 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 LIST with its element at index N removed. That is, remove + any element selected as (nth N LIST) from LIST and return the + result. + + This is a non-destructive operation: parts of LIST (but not + necessarily all of it) are copied as needed to avoid destructively + modifying it. + + See also: ‘-remove-at-indices’ (*note -remove-at-indices::), + ‘-remove’ (*note -remove::). + + (-remove-at 0 '(a b c)) + ⇒ (b c) + (-remove-at 1 '(a b c)) + ⇒ (a c) + (-remove-at 2 '(a b c)) + ⇒ (a b) + + -- Function: -remove-at-indices (indices list) + Return LIST with its elements at INDICES removed. That is, for + each index I in INDICES, remove any element selected as (nth I + LIST) from LIST. + + This is a non-destructive operation: parts of LIST (but not + necessarily all of it) are copied as needed to avoid destructively + modifying it. + + See also: ‘-remove-at’ (*note -remove-at::), ‘-remove’ (*note + -remove::). + + (-remove-at-indices '(0) '(a b c d e)) + ⇒ (b c d e) + (-remove-at-indices '(1 3) '(a b c d e)) + ⇒ (a c e) + (-remove-at-indices '(4 0 2) '(a b c d e)) + ⇒ (b d) + + +File: dash.info, Node: Reductions, Next: Unfolding, Prev: List to list, Up: Functions + +2.4 Reductions +============== + +Functions reducing lists to a single value (which may also be a list). + + -- Function: -reduce-from (fn init list) + Reduce the function FN across LIST, starting with INIT. Return the + result of applying FN to INIT and the first element of LIST, then + applying FN to that result and the second element, etc. If LIST is + empty, return INIT without calling FN. + + This function’s anaphoric counterpart is ‘--reduce-from’. + + For other folds, see also ‘-reduce’ (*note -reduce::) and + ‘-reduce-r’ (*note -reduce-r::). + + (-reduce-from #'- 10 '(1 2 3)) + ⇒ 4 + (-reduce-from #'list 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 init list) + Reduce the function FN across LIST in reverse, starting with INIT. + Return the result of applying FN to the last element of LIST and + INIT, then applying FN to the second-to-last element and the + previous result of FN, etc. That is, the first argument of FN is + the current element, and its second argument the accumulated value. + If LIST is empty, return INIT without calling FN. + + This function is like ‘-reduce-from’ (*note -reduce-from::) but the + operation associates from the right rather than left. In other + words, it starts from the end of LIST and flips the arguments to + FN. Conceptually, it is like replacing the conses in LIST with + applications of FN, and its last link with INIT, and evaluating the + resulting expression. + + This function’s anaphoric counterpart is ‘--reduce-r-from’. + + For other folds, see also ‘-reduce-r’ (*note -reduce-r::) and + ‘-reduce’ (*note -reduce::). + + (-reduce-r-from #'- 10 '(1 2 3)) + ⇒ -8 + (-reduce-r-from #'list 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) + Reduce the function FN across LIST. Return the result of applying + FN to the first two elements of LIST, then applying FN to that + result and the third element, etc. If LIST contains a single + element, return it without calling FN. If LIST is empty, return + the result of calling FN with no arguments. + + This function’s anaphoric counterpart is ‘--reduce’. + + For other folds, see also ‘-reduce-from’ (*note -reduce-from::) and + ‘-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) + Reduce the function FN across LIST in reverse. Return the result + of applying FN to the last two elements of LIST, then applying FN + to the third-to-last element and the previous result of FN, etc. + That is, the first argument of FN is the current element, and its + second argument the accumulated value. If LIST contains a single + element, return it without calling FN. If LIST is empty, return + the result of calling FN with no arguments. + + This function is like ‘-reduce’ (*note -reduce::) but the operation + associates from the right rather than left. In other words, it + starts from the end of LIST and flips the arguments to FN. + Conceptually, it is like replacing the conses in LIST with + applications of FN, ignoring its last link, and evaluating the + resulting expression. + + This function’s anaphoric counterpart is ‘--reduce-r’. + + For other folds, see also ‘-reduce-r-from’ (*note -reduce-r-from::) + and ‘-reduce’ (*note -reduce::). + + (-reduce-r #'- '(1 2 3 4)) + ⇒ -2 + (-reduce-r #'list '(1 2 3 4)) + ⇒ (1 (2 (3 4))) + (--reduce-r (format "%s-%d" acc it) '(1 2 3)) + ⇒ "3-2-1" + + -- Function: -reductions-from (fn init list) + Return a list of FN’s intermediate reductions across LIST. That + is, a list of the intermediate values of the accumulator when + ‘-reduce-from’ (*note -reduce-from::) (which see) is called with + the same arguments. + + This function’s anaphoric counterpart is ‘--reductions-from’. + + For other folds, see also ‘-reductions’ (*note -reductions::) and + ‘-reductions-r’ (*note -reductions-r::). + + (-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) + (--reductions-from (format "(FN %s %d)" acc it) "INIT" '(1 2 3)) + ⇒ ("INIT" "(FN INIT 1)" "(FN (FN INIT 1) 2)" "(FN (FN (FN INIT 1) 2) 3)") + + -- Function: -reductions-r-from (fn init list) + Return a list of FN’s intermediate reductions across reversed LIST. + That is, a list of the intermediate values of the accumulator when + ‘-reduce-r-from’ (*note -reduce-r-from::) (which see) is called + with the same arguments. + + This function’s anaphoric counterpart is ‘--reductions-r-from’. + + For other folds, see also ‘-reductions’ (*note -reductions::) and + ‘-reductions-r’ (*note -reductions-r::). + + (-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) + (--reductions-r-from (format "(FN %d %s)" it acc) "INIT" '(1 2 3)) + ⇒ ("(FN 1 (FN 2 (FN 3 INIT)))" "(FN 2 (FN 3 INIT))" "(FN 3 INIT)" "INIT") + + -- Function: -reductions (fn list) + Return a list of FN’s intermediate reductions across LIST. That + is, a list of the intermediate values of the accumulator when + ‘-reduce’ (*note -reduce::) (which see) is called with the same + arguments. + + This function’s anaphoric counterpart is ‘--reductions’. + + For other folds, see also ‘-reductions’ (*note -reductions::) and + ‘-reductions-r’ (*note -reductions-r::). + + (-reductions #'+ '(1 2 3 4)) + ⇒ (1 3 6 10) + (-reductions #'* '(1 2 3 4)) + ⇒ (1 2 6 24) + (--reductions (format "(FN %s %d)" acc it) '(1 2 3)) + ⇒ (1 "(FN 1 2)" "(FN (FN 1 2) 3)") + + -- Function: -reductions-r (fn list) + Return a list of FN’s intermediate reductions across reversed LIST. + That is, a list of the intermediate values of the accumulator when + ‘-reduce-r’ (*note -reduce-r::) (which see) is called with the same + arguments. + + This function’s anaphoric counterpart is ‘--reductions-r’. + + For other folds, see also ‘-reductions-r-from’ (*note + -reductions-r-from::) and ‘-reductions’ (*note -reductions::). + + (-reductions-r #'+ '(1 2 3 4)) + ⇒ (10 9 7 4) + (-reductions-r #'* '(1 2 3 4)) + ⇒ (24 24 12 4) + (--reductions-r (format "(FN %d %s)" it acc) '(1 2 3)) + ⇒ ("(FN 1 (FN 2 3))" "(FN 2 3)" 3) + + -- 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→ Wrong type argument: consp, nil + + -- 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→ Wrong type argument: consp, nil + + -- 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)) + ⇒ () + (-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)) + ⇒ () + (-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) + + -- Function: -frequencies (list) + Count the occurrences of each distinct element of LIST. + + Return an alist of (ELEMENT . N), where each ELEMENT occurs N + times in LIST. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that is non-‘nil’. + + See also ‘-count’ (*note -count::) and ‘-group-by’ (*note + -group-by::). + + (-frequencies ()) + ⇒ () + (-frequencies '(1 2 3 1 2 1)) + ⇒ ((1 . 3) (2 . 2) (3 . 1)) + (let ((-compare-fn #'string=)) (-frequencies '(a "a"))) + ⇒ ((a . 2)) + + +File: dash.info, Node: Unfolding, Next: Predicates, Prev: Reductions, Up: Functions + +2.5 Unfolding +============= + +Operations dual to reductions, building lists from a 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 the 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)) + + -- Function: -repeat (n x) + Return a new list of length N with each element being X. Return + ‘nil’ if N is less than 1. + + (-repeat 3 :a) + ⇒ (:a :a :a) + (-repeat 1 :a) + ⇒ (:a) + (-repeat 0 :a) + ⇒ () + + -- Function: -cycle (list) + Return an infinite circular copy of LIST. The returned list cycles + through the elements of LIST and repeats 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-lists (-cycle '(3)) '(1 2)) + ⇒ ((3 1) (3 2)) + + +File: dash.info, Node: Predicates, Next: Partitioning, Prev: Unfolding, Up: Functions + +2.6 Predicates +============== + +Reductions of one or more lists to a boolean value. + + -- Function: -some (pred list) + Return (PRED x) for the first LIST item where (PRED x) is + non-‘nil’, else ‘nil’. + + Alias: ‘-any’. + + This function’s anaphoric counterpart is ‘--some’. + + (-some #'stringp '(1 "2" 3)) + ⇒ t + (--some (string-match-p "x" it) '("foo" "axe" "xor")) + ⇒ 1 + (--some (= it-index 3) '(0 1 2)) + ⇒ nil + + -- Function: -every (pred list) + Return non-‘nil’ if PRED returns non-‘nil’ for all items in LIST. + If so, return the last such result of PRED. Otherwise, once an + item is reached for which PRED returns ‘nil’, return ‘nil’ without + calling PRED on any further LIST elements. + + This function is like ‘-every-p’, but on success returns the last + non-‘nil’ result of PRED instead of just ‘t’. + + This function’s anaphoric counterpart is ‘--every’. + + (-every #'numberp '(1 2 3)) + ⇒ t + (--every (string-match-p "x" it) '("axe" "xor")) + ⇒ 0 + (--every (= it it-index) '(0 1 3)) + ⇒ nil + + -- 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? #'numberp '(nil 0 t)) + ⇒ t + (-any? #'numberp '(nil t t)) + ⇒ 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’. + In the latter case, stop after the first X for which (PRED X) is + ‘nil’, without calling PRED on any subsequent elements of LIST. + + The similar function ‘-every’ (*note -every::) is more widely + useful, since it returns the last non-‘nil’ result of PRED instead + of just ‘t’ on success. + + Alias: ‘-all-p’, ‘-every-p’, ‘-every?’. + + This function’s anaphoric counterpart is ‘--all?’. + + (-all? #'numberp '(1 2 3)) + ⇒ t + (-all? #'numberp '(2 t 6)) + ⇒ nil + (--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 different LIST items both satisfy and do not satisfy + PRED. That is, if PRED returns both ‘nil’ for at least one item, + and non-‘nil’ for at least one other item in LIST. Return ‘nil’ if + all items satisfy the predicate or none of them do. + + 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 is non-‘nil’. As with ‘member’, the return value is + actually the tail of LIST whose car is ELEMENT. + + Alias: ‘-contains-p’. + + (-contains? '(1 2 3) 1) + ⇒ (1 2 3) + (-contains? '(1 2 3) 2) + ⇒ (2 3) + (-contains? '(1 2 3) 4) + ⇒ () + + -- Function: -is-prefix? (prefix list) + Return non-‘nil’ if PREFIX is a 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 a 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 + + -- Function: -cons-pair? (obj) + Return non-‘nil’ if OBJ is a true cons pair. That is, a cons (A . + B) where B is not a list. + + Alias: ‘-cons-pair-p’. + + (-cons-pair? '(1 . 2)) + ⇒ t + (-cons-pair? '(1 2)) + ⇒ nil + (-cons-pair? '(1)) + ⇒ nil + + +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) + Split LIST into two sublists after the Nth element. The result is + a list of two elements (TAKE DROP) where TAKE is a new list of the + first N elements of LIST, and DROP is the remaining elements of + LIST (not a copy). TAKE and DROP are like the results of ‘-take’ + (*note -take::) and ‘-drop’ (*note -drop::), respectively, but the + split is done in a single list traversal. + + (-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) + (-split-at 0 '(1 2 3 4 5)) + ⇒ (nil (1 2 3 4 5)) + + -- Function: -split-with (pred list) + Split LIST into a prefix satisfying PRED, and the rest. The first + sublist is the prefix of LIST with successive elements satisfying + PRED, and the second sublist is the remaining elements that do not. + The result is like performing + + ((-take-while PRED LIST) (-drop-while PRED LIST)) + + but in no more than a single pass through 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) + Split LIST into two sublists based on whether items satisfy PRED. + The result is like performing + + ((-filter PRED LIST) (-remove PRED LIST)) + + but in a single pass through 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) + Partition LIST into sublists of length N that are STEP items apart. + Like ‘-partition-all-in-steps’ (*note -partition-all-in-steps::), + but 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) + Partition LIST into sublists of length N that are STEP items apart. + Adjacent groups may overlap if N exceeds the STEP stride. Trailing + 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 LIST after each element for which PRED returns non-‘nil’. + + This function’s anaphoric counterpart is ‘--partition-after-pred’. + + (-partition-after-pred #'booleanp ()) + ⇒ () + (-partition-after-pred #'booleanp '(t t)) + ⇒ ((t) (t)) + (-partition-after-pred #'booleanp '(0 0 t t 0 t)) + ⇒ ((0 0 t) (t) (0 t)) + + -- Function: -partition-before-pred (pred list) + Partition directly before each time PRED is true on an element of + LIST. + + (-partition-before-pred #'booleanp ()) + ⇒ () + (-partition-before-pred #'booleanp '(0 t)) + ⇒ ((0) (t)) + (-partition-before-pred #'booleanp '(0 0 t 0 t t)) + ⇒ ((0 0) (t 0) (t) (t)) + + -- 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 +============ + +Functions retrieving or sorting based on list indices and related +predicates. + + -- Function: -elem-index (elem list) + Return the first index of ELEM in LIST. That is, the index within + LIST of the first element that is ‘equal’ to ELEM. Return ‘nil’ if + there is no such element. + + See also: ‘-find-index’ (*note -find-index::). + + (-elem-index 2 '(6 7 8 3 4)) + ⇒ nil + (-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 list of indices at which ELEM appears in LIST. That is, + the indices of all elements of LIST ‘equal’ to ELEM, in the same + ascending order as they appear in LIST. + + (-elem-indices 2 '(6 7 8 3 4 1)) + ⇒ () + (-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) + Return the index of the first item satisfying PRED in LIST. Return + ‘nil’ if no such item is found. + + PRED is called with one argument, the current list element, until + it returns non-‘nil’, at which point the search terminates. + + This function’s anaphoric counterpart is ‘--find-index’. + + See also: ‘-first’ (*note -first::), ‘-find-last-index’ (*note + -find-last-index::). + + (-find-index #'numberp '(a b c)) + ⇒ nil + (-find-index #'natnump '(1 0 -1)) + ⇒ 0 + (--find-index (> it 5) '(2 4 1 6 3 3 5 8)) + ⇒ 3 + + -- Function: -find-last-index (pred list) + Return the index of the last item satisfying PRED in LIST. Return + ‘nil’ if no such item is found. + + Predicate PRED is called with one argument each time, namely the + current list element. + + This function’s anaphoric counterpart is ‘--find-last-index’. + + See also: ‘-last’ (*note -last::), ‘-find-index’ (*note + -find-index::). + + (-find-last-index #'numberp '(a b c)) + ⇒ nil + (--find-last-index (> it 5) '(2 7 1 6 3 8 5 2)) + ⇒ 5 + (-find-last-index (-partial #'string< 'a) '(c b a)) + ⇒ 1 + + -- Function: -find-indices (pred list) + Return the list of indices in LIST satisfying PRED. + + Each element of LIST in turn is passed to PRED. If the result is + non-‘nil’, the index of that element in LIST is included in the + result. The returned indices are in ascending order, i.e., in the + same order as they appear in LIST. + + This function’s anaphoric counterpart is ‘--find-indices’. + + See also: ‘-find-index’ (*note -find-index::), ‘-elem-indices’ + (*note -elem-indices::). + + (-find-indices #'numberp '(a b c)) + ⇒ () + (-find-indices #'numberp '(8 1 d 2 b c a 3)) + ⇒ (0 1 3 7) + (--find-indices (> it 5) '(2 4 1 6 3 3 5 8)) + ⇒ (3 7) + + -- Function: -grade-up (comparator list) + Grade elements of LIST using COMPARATOR relation. This yields 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. This yields 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 (list1 list2) + Return a new list of distinct elements appearing in either LIST1 or + LIST2. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that is non-‘nil’. + + (-union '(1 2 3) '(3 4 5)) + ⇒ (1 2 3 4 5) + (-union '(1 2 2 4) ()) + ⇒ (1 2 4) + (-union '(1 1 2 2) '(4 4 3 2 1)) + ⇒ (1 2 4 3) + + -- Function: -difference (list1 list2) + Return a new list with the distinct members of LIST1 that are not + in LIST2. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that is 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 (list1 list2) + Return a new list of distinct elements appearing in both LIST1 and + LIST2. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that is non-‘nil’. + + (-intersection () ()) + ⇒ () + (-intersection '(1 2 3) '(4 5 6)) + ⇒ () + (-intersection '(1 2 2 3) '(4 3 3 2)) + ⇒ (2 3) + + -- Function: -powerset (list) + Return the power set of LIST. + + (-powerset ()) + ⇒ (nil) + (-powerset '(x y)) + ⇒ ((x y) (x) (y) nil) + (-powerset '(x y z)) + ⇒ ((x y z) (x y) (x z) (x) (y z) (y) (z) nil) + + -- Function: -permutations (list) + Return the distinct permutations of LIST. + + Duplicate elements of LIST are determined by ‘equal’, or by + ‘-compare-fn’ if that is non-‘nil’. + + (-permutations ()) + ⇒ (nil) + (-permutations '(a a b)) + ⇒ ((a a b) (a b a) (b a a)) + (-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 copy of LIST with all duplicate elements removed. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that is non-‘nil’. + + Alias: ‘-uniq’. + + (-distinct ()) + ⇒ () + (-distinct '(1 1 2 3 3)) + ⇒ (1 2 3) + (-distinct '(t t t)) + ⇒ (t) + + -- Function: -same-items? (list1 list2) + Return non-‘nil’ if LIST1 and LIST2 have the same distinct + elements. + + The order of the elements in the lists does not matter. The lists + may be of different lengths, i.e., contain duplicate elements. The + test for equality is done with ‘equal’, or with ‘-compare-fn’ if + that is non-‘nil’. + + Alias: ‘-same-items-p’. + + (-same-items? '(1 2 3) '(1 2 3)) + ⇒ t + (-same-items? '(1 1 2 3) '(3 3 2 1)) + ⇒ t + (-same-items? '(1 2 3) '(1 2 3 4)) + ⇒ nil + + +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 (left if N is negative). 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: -cons* (&rest args) + Make a new list from the elements of ARGS. The last 2 elements of + ARGS are used as the final cons of the result, so if the final + element of ARGS is not a list, the result is a dotted list. With + no ARGS, return ‘nil’. + + (-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 any ELEMENTS are given, append them 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: -iota (count &optional start step) + Return a list containing COUNT numbers. Starts from START and adds + STEP each time. The default START is zero, the default STEP is 1. + This function takes its name from the corresponding primitive in + the APL language. + + (-iota 6) + ⇒ (0 1 2 3 4 5) + (-iota 4 2.5 -2) + ⇒ (2.5 0.5 -1.5 -3.5) + (-iota -1) + error→ Wrong type argument: natnump, -1 + + -- Function: -zip-with (fn list1 list2) + Zip LIST1 and LIST2 into a new list using the function FN. That + is, apply FN pairwise taking as first argument the next element of + LIST1 and as second argument the next element of LIST2 at the + corresponding position. The result is as long as the shorter list. + + This function’s anaphoric counterpart is ‘--zip-with’. + + For other zips, see also ‘-zip-lists’ (*note -zip-lists::) and + ‘-zip-fill’ (*note -zip-fill::). + + (-zip-with #'+ '(1 2 3 4) '(5 6 7)) + ⇒ (6 8 10) + (-zip-with #'cons '(1 2 3) '(4 5 6 7)) + ⇒ ((1 . 4) (2 . 5) (3 . 6)) + (--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde)) + ⇒ ("Batman & Robin" "Jekyll & Hyde") + + -- Function: -zip-pair (list1 list2) + Zip LIST1 and LIST2 together. + + Make a pair with the head of each list, followed by a pair with the + second element of each list, and so on. The number of pairs + returned is equal to the length of the shorter input list. + + See also: ‘-zip-lists’ (*note -zip-lists::). + + (-zip-pair '(1 2 3 4) '(5 6 7)) + ⇒ ((1 . 5) (2 . 6) (3 . 7)) + (-zip-pair '(1 2 3) '(4 5 6)) + ⇒ ((1 . 4) (2 . 5) (3 . 6)) + (-zip-pair '(1 2) '(3)) + ⇒ ((1 . 3)) + + -- Function: -zip-lists (&rest lists) + Zip LISTS together. + + Group the head of each list, followed by the second element of each + list, and so on. The number of returned groupings is equal to the + length of the shortest input list, and the length of each grouping + is equal to the number of input LISTS. + + The return value is always a list of proper lists, in contrast to + ‘-zip’ (*note -zip::) which returns a list of dotted pairs when + only two input LISTS are provided. + + See also: ‘-zip-pair’ (*note -zip-pair::). + + (-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-lists-fill (fill-value &rest lists) + Zip LISTS together, padding shorter lists with FILL-VALUE. This is + like ‘-zip-lists’ (*note -zip-lists::) (which see), except it + retains all elements at positions beyond the end of the shortest + list. The number of returned groupings is equal to the length of + the longest input list, and the length of each grouping is equal to + the number of input LISTS. + + (-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) + ⇒ ((1 3 6) (2 4 0) (0 5 0)) + (-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) + ⇒ ((1 3 5) (2 4 6)) + (-zip-lists-fill 0 '(1 2 3) nil) + ⇒ ((1 0) (2 0) (3 0)) + + -- Function: -zip (&rest lists) + Zip LISTS together. + + Group the head of each list, followed by the second element of each + list, and so on. The number of returned groupings is equal to the + length of the shortest input list, and the number of items in each + grouping is equal to the number of input LISTS. + + If only two LISTS are provided as arguments, return the groupings + as a list of dotted pairs. Otherwise, return the groupings as a + list of proper lists. + + Since the return value changes form depending on the number of + arguments, it is generally recommended to use ‘-zip-lists’ (*note + -zip-lists::) instead, or ‘-zip-pair’ (*note -zip-pair::) if a list + of dotted pairs is desired. + + See also: ‘-unzip’ (*note -unzip::). + + (-zip '(1 2 3 4) '(5 6 7) '(8 9)) + ⇒ ((1 5 8) (2 6 9)) + (-zip '(1 2 3) '(4 5 6) '(7 8 9)) + ⇒ ((1 4 7) (2 5 8) (3 6 9)) + (-zip '(1 2 3)) + ⇒ ((1) (2) (3)) + + -- Function: -zip-fill (fill-value &rest lists) + Zip LISTS together, padding shorter lists with FILL-VALUE. This is + like ‘-zip’ (*note -zip::) (which see), except it retains all + elements at positions beyond the end of the shortest list. The + number of returned groupings is equal to the length of the longest + input list, and the length of each grouping is equal to the number + of input LISTS. + + Since the return value changes form depending on the number of + arguments, it is generally recommended to use ‘-zip-lists-fill’ + (*note -zip-lists-fill::) instead, unless a list of dotted pairs is + explicitly desired. + + (-zip-fill 0 '(1 2 3) '(4 5)) + ⇒ ((1 . 4) (2 . 5) (3 . 0)) + (-zip-fill 0 () '(1 2 3)) + ⇒ ((0 . 1) (0 . 2) (0 . 3)) + (-zip-fill 0 '(1 2) '(3 4) '(5 6)) + ⇒ ((1 3 5) (2 4 6)) + + -- Function: -unzip-lists (lists) + Unzip LISTS. + + This works just like ‘-zip-lists’ (*note -zip-lists::) (which see), + but takes a list of lists instead of a variable number of + arguments, such that + + (-unzip-lists (-zip-lists ARGS...)) + + is identity (given that the lists comprising ARGS are of the same + length). + + (-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) + ⇒ ((1 2) (3 4) (5 6)) + (-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) + ⇒ ((1 4 6 8) (2 5 7 9)) + (-unzip-lists '((1 2 3) (4 5 6))) + ⇒ ((1 4) (2 5) (3 6)) + + -- Function: -unzip (lists) + Unzip LISTS. + + This works just like ‘-zip’ (*note -zip::) (which see), 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 of the same length, and that + ‘-zip’ (*note -zip::) is not called with two arguments, because of + the caveat described in its docstring). + + Note in particular that calling ‘-unzip’ (*note -unzip::) on a list + of two lists will return a list of dotted pairs. + + Since the return value changes form depending on the number of + LISTS, it is generally recommended to use ‘-unzip-lists’ (*note + -unzip-lists::) instead. + + (-unzip (-zip '(1 2) '(3 4) '(5 6))) + ⇒ ((1 . 2) (3 . 4) (5 . 6)) + (-unzip '((1 2 3) (4 5 6))) + ⇒ ((1 . 4) (2 . 5) (3 . 6)) + (-unzip '((1 2 3) (4 5) (6 7) (8 9))) + ⇒ ((1 4 6 8) (2 5 7 9)) + + -- Function: -pad (fill-value &rest lists) + Pad each of LISTS with FILL-VALUE until they all have equal + lengths. + + Ensure all LISTS are as long as the longest one by repeatedly + appending FILL-VALUE to the shorter lists, and return the resulting + LISTS. + + (-pad 0 ()) + ⇒ (nil) + (-pad 0 '(1 2) '(3 4)) + ⇒ ((1 2) (3 4)) + (-pad 0 '(1 2) '(3 4 5 6) '(7 8 9)) + ⇒ ((1 2 0 0) (3 4 5 6) (7 8 9 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 item in LIST for which PRED returns non-‘nil’. + Return ‘nil’ if no such element is found. + + To get the first item in the list no questions asked, use + ‘-first-item’ (*note -first-item::). + + Alias: ‘-find’. + + This function’s anaphoric counterpart is ‘--first’. + + (-first #'natnump '(-1 0 1)) + ⇒ 0 + (-first #'null '(1 2 3)) + ⇒ nil + (--first (> it 2) '(1 2 3)) + ⇒ 3 + + -- 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::), etc. + + (-first-item ()) + ⇒ () + (-first-item '(1 2 3 4 5)) + ⇒ 1 + (let ((list (list 1 2 3))) (setf (-first-item list) 5) list) + ⇒ (5 2 3) + + -- Function: -second-item (list) + Return the second item of LIST, or ‘nil’ if LIST is too short. + + See also: ‘-first-item’ (*note -first-item::), ‘-third-item’ (*note + -third-item::), etc. + + (-second-item ()) + ⇒ () + (-second-item '(1 2 3 4 5)) + ⇒ 2 + (let ((list (list 1 2))) (setf (-second-item list) 5) list) + ⇒ (1 5) + + -- Function: -third-item (list) + Return the third item of LIST, or ‘nil’ if LIST is too short. + + See also: ‘-second-item’ (*note -second-item::), ‘-fourth-item’ + (*note -fourth-item::), etc. + + (-third-item ()) + ⇒ () + (-third-item '(1 2)) + ⇒ () + (-third-item '(1 2 3 4 5)) + ⇒ 3 + + -- Function: -fourth-item (list) + Return the fourth item of LIST, or ‘nil’ if LIST is too short. + + See also: ‘-third-item’ (*note -third-item::), ‘-fifth-item’ (*note + -fifth-item::), etc. + + (-fourth-item ()) + ⇒ () + (-fourth-item '(1 2 3)) + ⇒ () + (-fourth-item '(1 2 3 4 5)) + ⇒ 4 + + -- Function: -fifth-item (list) + Return the fifth item of LIST, or ‘nil’ if LIST is too short. + + See also: ‘-fourth-item’ (*note -fourth-item::), ‘-last-item’ + (*note -last-item::), etc. + + (-fifth-item ()) + ⇒ () + (-fifth-item '(1 2 3 4)) + ⇒ () + (-fifth-item '(1 2 3 4 5)) + ⇒ 5 + + -- Function: -last-item (list) + Return the last item of LIST, or ‘nil’ on an empty list. + + See also: ‘-first-item’ (*note -first-item::), etc. + + (-last-item ()) + ⇒ () + (-last-item '(1 2 3 4 5)) + ⇒ 5 + (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 (arg) + Ensure ARG is a list. If ARG is already a list, return it as is + (not a copy). Otherwise, return a new list with ARG as its only + element. + + Another supported calling convention is (-list &rest ARGS). In + this case, if ARG is not a list, a new list with all of ARGS as + elements is returned. This use is supported for backward + compatibility and is otherwise deprecated. + + (-list 1) + ⇒ (1) + (-list ()) + ⇒ () + (-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))) + ⇒ ((1) (2) (3)) + (let ((l '((starwars scifi) (jedi starwars warrior)))) (--fix (-uniq (--mapcat (cons it (cdr (assq it l))) 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) '("" ("

" "text" "

") "")) + ⇒ (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 "")))) '(body (p "some words") (div "more" (b "bold") "words"))) + ⇒ "

some words

more bold words
" + + -- 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) "}" '((elisp-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam))))) + ⇒ "{elisp-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 (list (list 1))) (b (-clone a))) (setcar (car a) 2) b) + ⇒ ((1)) + + +File: dash.info, Node: Threading macros, Next: Binding, Prev: Tree operations, Up: Functions + +2.12 Threading macros +===================== + +Macros that conditionally combine sequential forms for brevity or +readability. + + -- 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 the 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--> (expr &rest forms) + Thread EXPR through FORMS via ‘-->’ (*note -->::), while the result + is non-‘nil’. When EXPR evaluates to non-‘nil’, thread the result + through the first of FORMS, and when that result is non-‘nil’, + thread it through the next form, etc. + + (-some--> "def" (concat "abc" it "ghi")) + ⇒ "abcdefghi" + (-some--> nil (concat "abc" it "ghi")) + ⇒ nil + (-some--> '(0 1) (-remove #'natnump it) (append it it) (-map #'1+ it)) + ⇒ () + + -- Macro: -doto (init &rest forms) + Evaluate INIT and pass it as argument to FORMS with ‘->’ (*note + ->::). The RESULT of evaluating INIT is threaded through each of + FORMS individually using ‘->’ (*note ->::), which see. The return + value is RESULT, which FORMS may have modified by side effect. + + (-doto (list 1 2 3) pop pop) + ⇒ (3) + (-doto (cons 1 2) (setcar 3) (setcdr 4)) + ⇒ (3 . 4) + (gethash 'k (--doto (make-hash-table) (puthash 'k 'v it))) + ⇒ v + + +File: dash.info, Node: Binding, Next: Side effects, Prev: Threading macros, Up: Functions + +2.13 Binding +============ + +Macros that combine ‘let’ and ‘let*’ with destructuring and 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::). + + (-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::). + + (-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 a description of the 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 ([match-form val] ...) + 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. + + (let (a) (-setq a 1) a) + ⇒ 1 + (let (a b) (-setq (a b) (list 1 2)) (list a b)) + ⇒ (1 2) + (let (c) (-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 on each element of LIST. Return ‘nil’; this function is + intended for side effects. + + Its anaphoric counterpart is ‘--each’. + + For access to the current element’s index in LIST, see + ‘-each-indexed’ (*note -each-indexed::). + + (let (l) (-each '(1 2 3) (lambda (x) (push x l))) l) + ⇒ (3 2 1) + (let (l) (--each '(1 2 3) (push it l)) l) + ⇒ (3 2 1) + (-each '(1 2 3) #'identity) + ⇒ nil + + -- Function: -each-while (list pred fn) + Call FN on each ITEM in LIST, while (PRED ITEM) is non-‘nil’. Once + an ITEM is reached for which PRED returns ‘nil’, FN is no longer + called. Return ‘nil’; this function is intended for side effects. + + Its anaphoric counterpart is ‘--each-while’. + + (let (l) (-each-while '(2 4 5 6) #'even? (lambda (x) (push x l))) l) + ⇒ (4 2) + (let (l) (--each-while '(1 2 3 4) (< it 3) (push it l)) l) + ⇒ (2 1) + (let ((s 0)) (--each-while '(1 3 4 5) (< it 5) (setq s (+ s it))) s) + ⇒ 8 + + -- Function: -each-indexed (list fn) + Call FN on each index and element of LIST. For each ITEM at INDEX + in LIST, call (funcall FN INDEX ITEM). Return ‘nil’; this function + is intended for side effects. + + See also: ‘-map-indexed’ (*note -map-indexed::). + + (let (l) (-each-indexed '(a b c) (lambda (i x) (push (list x i) l))) l) + ⇒ ((c 2) (b 1) (a 0)) + (let (l) (--each-indexed '(a b c) (push (list it it-index) l)) l) + ⇒ ((c 2) (b 1) (a 0)) + (let (l) (--each-indexed () (push it l)) l) + ⇒ () + + -- Function: -each-r (list fn) + Call FN on each element of LIST in reversed order. Return ‘nil’; + this function is intended for side effects. + + Its anaphoric counterpart is ‘--each-r’. + + (let (l) (-each-r '(1 2 3) (lambda (x) (push x l))) l) + ⇒ (1 2 3) + (let (l) (--each-r '(1 2 3) (push it l)) l) + ⇒ (1 2 3) + (-each-r '(1 2 3) #'identity) + ⇒ nil + + -- Function: -each-r-while (list pred fn) + Call FN on each ITEM in reversed LIST, while (PRED ITEM) is + non-‘nil’. Once an ITEM is reached for which PRED returns ‘nil’, + FN is no longer called. Return ‘nil’; this function is intended + for side effects. + + Its anaphoric counterpart is ‘--each-r-while’. + + (let (l) (-each-r-while '(2 4 5 6) #'even? (lambda (x) (push x l))) l) + ⇒ (6) + (let (l) (--each-r-while '(1 2 3 4) (>= it 3) (push it l)) l) + ⇒ (3 4) + (let ((s 0)) (--each-r-while '(1 2 3 5) (> it 1) (setq s (+ s it))) s) + ⇒ 10 + + -- Function: -dotimes (num fn) + Call FN NUM times, presumably for side effects. FN is called with + a single argument on successive integers running from 0, inclusive, + to NUM, exclusive. FN is not called if NUM is less than 1. + + This function’s anaphoric counterpart is ‘--dotimes’. + + (let (s) (-dotimes 3 (lambda (n) (push n s))) s) + ⇒ (2 1 0) + (let (s) (-dotimes 0 (lambda (n) (push n s))) s) + ⇒ () + (let (s) (--dotimes 5 (push it s)) s) + ⇒ (4 3 2 1 0) + + +File: dash.info, Node: Destructive operations, Next: Function combinators, Prev: Side effects, Up: Functions + +2.15 Destructive operations +=========================== + +Macros that modify variables holding lists. + + -- 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 +========================= + +Functions that manipulate and compose other functions. + + -- Function: -partial (fun &rest args) + Return a function that is a partial application of FUN to ARGS. + ARGS is a list of the first N arguments to pass to FUN. The result + is a new function which does the same as FUN, except that the first + N arguments are fixed at the values with which this function was + called. + + (funcall (-partial #'+ 5)) + ⇒ 5 + (funcall (-partial #'- 5) 3) + ⇒ 2 + (funcall (-partial #'+ 5 2) 3) + ⇒ 10 + + -- Function: -rpartial (fn &rest args) + Return a function that is a partial application of FN to ARGS. + ARGS is a list of the last N arguments to pass to FN. The result + is a new function which does the same as FN, except that the last N + arguments are fixed at the values with which this function was + called. This is like ‘-partial’ (*note -partial::), except the + arguments are fixed starting from the right rather than the left. + + (funcall (-rpartial #'- 5)) + ⇒ -5 + (funcall (-rpartial #'- 5) 8) + ⇒ 3 + (funcall (-rpartial #'- 5 2) 10) + ⇒ 3 + + -- Function: -juxt (&rest fns) + Return a function that is the juxtaposition of FNS. The returned + function takes a variable number of ARGS, applies each of FNS in + turn to ARGS, and returns the list of results. + + (funcall (-juxt) 1 2) + ⇒ () + (funcall (-juxt #'+ #'- #'* #'/) 7 5) + ⇒ (12 2 35 1) + (mapcar (-juxt #'number-to-string #'1+) '(1 2)) + ⇒ (("1" 2) ("2" 3)) + + -- Function: -compose (&rest fns) + Compose FNS into a single composite function. Return a function + that takes a variable number of ARGS, applies the last function in + FNS to ARGS, and returns the result of calling each remaining + function on the result of the previous function, right-to-left. If + no FNS are given, return a variadic ‘identity’ function. + + (funcall (-compose #'- #'1+ #'+) 1 2 3) + ⇒ -7 + (funcall (-compose #'identity #'1+) 3) + ⇒ 4 + (mapcar (-compose #'not #'stringp) '(nil "")) + ⇒ (t nil) + + -- Function: -applify (fn) + Return a function that applies FN to a single list of args. This + changes the arity of FN from taking N distinct arguments to taking + 1 argument which is a list of N arguments. + + (funcall (-applify #'+) nil) + ⇒ 0 + (mapcar (-applify #'+) '((1 1 1) (1 2 3) (5 5 5))) + ⇒ (3 6 15) + (funcall (-applify #'<) '(3 6)) + ⇒ t + + -- Function: -on (op trans) + Return a function that calls TRANS on each arg and OP on the + results. The returned function takes a variable number of + arguments, calls the function TRANS on each one in turn, and then + passes those results as the list of arguments to OP, in the same + order. + + For example, the following pairs of expressions are morally + equivalent: + + (funcall (-on #’+ #’1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3)) (funcall + (-on #’+ #’1+)) = (+) + + (-sort (-on #'< #'length) '((1 2 3) (1) (1 2))) + ⇒ ((1) (1 2) (1 2 3)) + (funcall (-on #'min #'string-to-number) "22" "2" "1" "12") + ⇒ 1 + (-min-by (-on #'> #'length) '((1 2 3) (4) (1 2))) + ⇒ (4) + + -- Function: -flip (fn) + Return a function that calls FN with its arguments reversed. The + returned function takes the same number of arguments as FN. + + For example, the following two expressions are morally equivalent: + + (funcall (-flip #’-) 1 2) = (- 2 1) + + See also: ‘-rotate-args’ (*note -rotate-args::). + + (-sort (-flip #'<) '(4 3 6 1)) + ⇒ (6 4 3 1) + (funcall (-flip #'-) 3 2 1 10) + ⇒ 4 + (funcall (-flip #'1+) 1) + ⇒ 2 + + -- Function: -rotate-args (n fn) + Return a function that calls FN with args rotated N places to the + right. The returned function takes the same number of arguments as + FN, rotates the list of arguments N places to the right (left if N + is negative) just like ‘-rotate’ (*note -rotate::), and applies FN + to the result. + + See also: ‘-flip’ (*note -flip::). + + (funcall (-rotate-args -1 #'list) 1 2 3 4) + ⇒ (2 3 4 1) + (funcall (-rotate-args 1 #'-) 1 10 100) + ⇒ 89 + (funcall (-rotate-args 2 #'list) 3 4 5 1 2) + ⇒ (1 2 3 4 5) + + -- 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 + (mapcar (-const 1) '("a" "b" "c" "d")) + ⇒ (1 1 1 1) + (-sum (mapcar (-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 vector string)) + ⇒ ((1 2 3) [1 2 3] "\1\2\3") + + -- Function: -not (pred) + Return a predicate that negates the result of PRED. The returned + predicate passes its arguments to PRED. If PRED returns ‘nil’, the + result is non-‘nil’; otherwise the result is ‘nil’. + + See also: ‘-andfn’ (*note -andfn::) and ‘-orfn’ (*note -orfn::). + + (funcall (-not #'numberp) "5") + ⇒ t + (-sort (-not #'<) '(5 2 1 0 6)) + ⇒ (6 5 2 1 0) + (-filter (-not (-partial #'< 4)) '(1 2 3 4 5 6 7 8)) + ⇒ (1 2 3 4) + + -- Function: -orfn (&rest preds) + Return a predicate that returns the first non-‘nil’ result of + PREDS. The returned predicate takes a variable number of + arguments, passes them to each predicate in PREDS in turn until one + of them returns non-‘nil’, and returns that non-‘nil’ result + without calling the remaining PREDS. If all PREDS return ‘nil’, or + if no PREDS are given, the returned predicate returns ‘nil’. + + See also: ‘-andfn’ (*note -andfn::) and ‘-not’ (*note -not::). + + (-filter (-orfn #'natnump #'booleanp) '(1 nil "a" -4 b c t)) + ⇒ (1 nil t) + (funcall (-orfn #'symbolp (-cut string-match-p "x" <>)) "axe") + ⇒ 1 + (funcall (-orfn #'= #'+) 1 1) + ⇒ t + + -- Function: -andfn (&rest preds) + Return a predicate that returns non-‘nil’ if all PREDS do so. The + returned predicate P takes a variable number of arguments and + passes them to each predicate in PREDS in turn. If any one of + PREDS returns ‘nil’, P also returns ‘nil’ without calling the + remaining PREDS. If all PREDS return non-‘nil’, P returns the last + such value. If no PREDS are given, P always returns non-‘nil’. + + See also: ‘-orfn’ (*note -orfn::) and ‘-not’ (*note -not::). + + (-filter (-andfn #'numberp (-cut < <> 5)) '(a 1 b 6 c 2)) + ⇒ (1 2) + (mapcar (-andfn #'numberp #'1+) '(a 1 b 6)) + ⇒ (nil 2 nil 7) + (funcall (-andfn #'= #'+) 1 1) + ⇒ 2 + + -- 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=) 0.7) + ⇒ 0.7390851332151607 + (funcall (-fixfn (lambda (x) (expt (+ x 10) 0.25))) 2.0) + ⇒ 1.8555845286409378 + (funcall (-fixfn #'sin #'approx=) 0.1) + ⇒ (halted . t) + + -- Function: -prodfn (&rest fns) + Return a function that applies each of FNS to each of a list of + arguments. + + Takes a list of N functions and returns a function that takes a + list of length N, applying Ith function to Ith 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))) + ⇒ ((0 3) (2 5) (4 7)) + (apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) + ⇒ 6 + + +File: dash.info, Node: Development, Next: FDL, Prev: Functions, Up: Top + +3 Development +************* + +The Dash repository is hosted on GitHub at +. + +* Menu: + +* Contribute:: How to contribute. +* Contributors:: List of contributors. + + +File: dash.info, Node: Contribute, Next: Contributors, Up: Development + +3.1 Contribute +============== + +Yes, please do. Pure functions in the list manipulation realm only, +please. There’s a suite of examples/tests in ‘dev/examples.el’, so +remember to add tests for your additions, or they may get broken later. + + Run the tests with ‘make check’. Regenerate the docs with ‘make +docs’. Contributors are encouraged to install these commands as a Git +pre-commit hook, so that the tests are always running and the docs are +always in sync: + + $ cp dev/pre-commit.sh .git/hooks/pre-commit + + Oh, and don’t edit ‘README.md’ or ‘dash.texi’ directly, as they are +auto-generated. Instead, change their respective templates +‘readme-template.md’ or ‘dash-template.texi’. + + To ensure that Dash can be distributed with GNU ELPA or Emacs, we +require that all contributors assign copyright to the Free Software +Foundation. For more on this, *note (emacs)Copyright Assignment::. + + +File: dash.info, Node: Contributors, Prev: Contribute, Up: Development + +3.2 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 a variadic version of ‘-zip’. + • Fredrik Bergroth (https://github.com/fbergroth) made the ‘-if-let’ + family use ‘-let’ destructuring and improved the script for + generating documentation. + • Mark Oteiza (https://github.com/holomorph) contributed ‘-iota’ and + 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. + • Cam Saul (https://github.com/camsaul) contributed ‘-some->’, + ‘-some->>’, and ‘-some-->’. + • Basil L. Contovounesios (https://github.com/basil-conto) + contributed ‘-common-prefix’, ‘-common-suffix’, and various other + improvements. + • Paul Pogonyshev (https://github.com/doublep) contributed ‘-each-r’ + and ‘-each-r-while’. + + Thanks! + + New contributors are very welcome. *Note Contribute::. + + +File: dash.info, Node: FDL, Next: GPL, Prev: Development, Up: Top + +Appendix A GNU Free Documentation License +***************************************** + + Version 1.3, 3 November 2008 + + Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 0. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document “free” in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by others. + + This License is a kind of “copyleft”, which means that derivative + works of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to + software manuals; it can be used for any textual work, regardless + of subject matter or whether it is published as a printed book. We + recommend this License principally for works whose purpose is + instruction or reference. + + 1. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it can + be distributed under the terms of this License. Such a notice + grants a world-wide, royalty-free license, unlimited in duration, + to use that work under the conditions stated herein. The + “Document”, below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as “you”. You accept + the license if you copy, modify or distribute the work in a way + requiring permission under copyright law. + + A “Modified Version” of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A “Secondary Section” is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document’s overall + subject (or to related matters) and contains nothing that could + fall directly within that overall subject. (Thus, if the Document + is in part a textbook of mathematics, a Secondary Section may not + explain any mathematics.) The relationship could be a matter of + historical connection with the subject or with related matters, or + of legal, commercial, philosophical, ethical or political position + regarding them. + + The “Invariant Sections” are certain Secondary Sections whose + titles are designated, as being those of Invariant Sections, in the + notice that says that the Document is released under this License. + If a section does not fit the above definition of Secondary then it + is not allowed to be designated as Invariant. The Document may + contain zero Invariant Sections. If the Document does not identify + any Invariant Sections then there are none. + + The “Cover Texts” are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice + that says that the Document is released under this License. A + Front-Cover Text may be at most 5 words, and a Back-Cover Text may + be at most 25 words. + + A “Transparent” copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images composed + of pixels) generic paint programs or (for drawings) some widely + available drawing editor, and that is suitable for input to text + formatters or for automatic translation to a variety of formats + suitable for input to text formatters. A copy made in an otherwise + Transparent file format whose markup, or absence of markup, has + been arranged to thwart or discourage subsequent modification by + readers is not Transparent. An image format is not Transparent if + used for any substantial amount of text. A copy that is not + “Transparent” is called “Opaque”. + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTeX input format, + SGML or XML using a publicly available DTD, and standard-conforming + simple HTML, PostScript or PDF designed for human modification. + Examples of transparent image formats include PNG, XCF and JPG. + Opaque formats include proprietary formats that can be read and + edited only by proprietary word processors, SGML or XML for which + the DTD and/or processing tools are not generally available, and + the machine-generated HTML, PostScript or PDF produced by some word + processors for output purposes only. + + The “Title Page” means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, “Title + Page” means the text near the most prominent appearance of the + work’s title, preceding the beginning of the body of the text. + + The “publisher” means any person or entity that distributes copies + of the Document to the public. + + A section “Entitled XYZ” means a named subunit of the Document + whose title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) + To “Preserve the Title” of such a section when you modify the + Document means that it remains a section “Entitled XYZ” according + to this definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and + has no effect on the meaning of this License. + + 2. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You + may not use technical measures to obstruct or control the reading + or further copying of the copies you make or distribute. However, + you may accept compensation in exchange for copies. If you + distribute a large enough number of copies you must also follow the + conditions in section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + + 3. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly + have printed covers) of the Document, numbering more than 100, and + the Document’s license notice requires Cover Texts, you must + enclose the copies in covers that carry, clearly and legibly, all + these Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also clearly + and legibly identify you as the publisher of these copies. The + front cover must present the full title with all words of the title + equally prominent and visible. You may add other material on the + covers in addition. Copying with changes limited to the covers, as + long as they preserve the title of the Document and satisfy these + conditions, can be treated as verbatim copying in other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a machine-readable + Transparent copy along with each Opaque copy, or state in or with + each Opaque copy a computer-network location from which the general + network-using public has access to download using public-standard + network protocols a complete Transparent copy of the Document, free + of added material. If you use the latter option, you must take + reasonably prudent steps, when you begin distribution of Opaque + copies in quantity, to ensure that this Transparent copy will + remain thus accessible at the stated location until at least one + year after the last time you distribute an Opaque copy (directly or + through your agents or retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of copies, + to give them a chance to provide you with an updated version of the + Document. + + 4. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document + under the conditions of sections 2 and 3 above, provided that you + release the Modified Version under precisely this License, with the + Modified Version filling the role of the Document, thus licensing + distribution and modification of the Modified Version to whoever + possesses a copy of it. In addition, you must do these things in + the Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of previous + versions (which should, if there were any, be listed in the + History section of the Document). You may use the same title + as a previous version if the original publisher of that + version gives permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the + principal authors of the Document (all of its principal + authors, if it has fewer than five), unless they release you + from this requirement. + + C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in + the Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document’s + license notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled “History”, Preserve its Title, + and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on the + Title Page. If there is no section Entitled “History” in the + Document, create one stating the title, year, authors, and + publisher of the Document as given on its Title Page, then add + an item describing the Modified Version as stated in the + previous sentence. + + J. Preserve the network location, if any, given in the Document + for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for + previous versions it was based on. These may be placed in the + “History” section. You may omit a network location for a work + that was published at least four years before the Document + itself, or if the original publisher of the version it refers + to gives permission. + + K. For any section Entitled “Acknowledgements” or “Dedications”, + Preserve the Title of the section, and preserve in the section + all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, unaltered + in their text and in their titles. Section numbers or the + equivalent are not considered part of the section titles. + + M. Delete any section Entitled “Endorsements”. Such a section + may not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled + “Endorsements” or to conflict in title with any Invariant + Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option designate + some or all of these sections as invariant. To do this, add their + titles to the list of Invariant Sections in the Modified Version’s + license notice. These titles must be distinct from any other + section titles. + + You may add a section Entitled “Endorsements”, provided it contains + nothing but endorsements of your Modified Version by various + parties—for example, statements of peer review or that the text has + been approved by an organization as the authoritative definition of + a standard. + + You may add a passage of up to five words as a Front-Cover Text, + and a passage of up to 25 words as a Back-Cover Text, to the end of + the list of Cover Texts in the Modified Version. Only one passage + of Front-Cover Text and one of Back-Cover Text may be added by (or + through arrangements made by) any one entity. If the Document + already includes a cover text for the same cover, previously added + by you or by arrangement made by the same entity you are acting on + behalf of, you may not add another; but you may replace the old + one, on explicit permission from the previous publisher that added + the old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + + 5. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination all + of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice, and that you preserve all + their Warranty Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the + original author or publisher of that section if known, or else a + unique number. Make the same adjustment to the section titles in + the list of Invariant Sections in the license notice of the + combined work. + + In the combination, you must combine any sections Entitled + “History” in the various original documents, forming one section + Entitled “History”; likewise combine any sections Entitled + “Acknowledgements”, and any sections Entitled “Dedications”. You + must delete all sections Entitled “Endorsements.” + + 6. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the documents + in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert + a copy of this License into the extracted document, and follow this + License in all other respects regarding verbatim copying of that + document. + + 7. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of a + storage or distribution medium, is called an “aggregate” if the + copyright resulting from the compilation is not used to limit the + legal rights of the compilation’s users beyond what the individual + works permit. When the Document is included in an aggregate, this + License does not apply to the other works in the aggregate which + are not themselves derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document’s Cover Texts may be placed + on covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket + the whole aggregate. + + 8. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warranty Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled “Acknowledgements”, + “Dedications”, or “History”, the requirement (section 4) to + Preserve its Title (section 1) will typically require changing the + actual title. + + 9. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, or distribute it is void, + and will automatically terminate your rights under this License. + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from + that copyright holder, and you cure the violation prior to 30 days + after your receipt of the notice. + + Termination of your rights under this section does not terminate + the licenses of parties who have received copies or rights from you + under this License. If your rights have been terminated and not + permanently reinstated, receipt of a copy of some or all of the + same material does not give you any rights to use it. + + 10. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + . + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered + version of this License “or any later version” applies to it, you + have the option of following the terms and conditions either of + that specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If the + Document does not specify a version number of this License, you may + choose any version ever published (not as a draft) by the Free + Software Foundation. If the Document specifies that a proxy can + decide which future versions of this License can be used, that + proxy’s public statement of acceptance of a version permanently + authorizes you to choose that version for the Document. + + 11. RELICENSING + + “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any + World Wide Web server that publishes copyrightable works and also + provides prominent facilities for anybody to edit those works. A + public wiki that anybody can edit is an example of such a server. + A “Massive Multiauthor Collaboration” (or “MMC”) contained in the + site means any set of copyrightable works thus published on the MMC + site. + + “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 + license published by Creative Commons Corporation, a not-for-profit + corporation with a principal place of business in San Francisco, + California, as well as future copyleft versions of that license + published by that same organization. + + “Incorporate” means to publish or republish a Document, in whole or + in part, as part of another Document. + + An MMC is “eligible for relicensing” if it is licensed under this + License, and if all works that were first published under this + License somewhere other than this MMC, and subsequently + incorporated in whole or in part into the MMC, (1) had no cover + texts or invariant sections, and (2) were thus incorporated prior + to November 1, 2008. + + The operator of an MMC Site may republish an MMC contained in the + site under CC-BY-SA on the same site at any time before August 1, + 2009, provided the MMC is eligible for relicensing. + +ADDENDUM: How to use this License for your documents +==================================================== + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + + If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the “with...Texts.” line with this: + + with the Invariant Sections being LIST THEIR TITLES, with + the Front-Cover Texts being LIST, and with the Back-Cover Texts + being LIST. + + If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + + If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU General Public License, to permit +their use in free software. + + +File: dash.info, Node: GPL, Next: Index, Prev: FDL, Up: Top + +Appendix B GNU General Public License +************************************* + + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies of this + license document, but changing it is not allowed. + +Preamble +======== + +The GNU General Public License is a free, copyleft license for software +and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program—to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers’ and authors’ protection, the GPL clearly explains +that there is no warranty for this free software. For both users’ and +authors’ sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users’ freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS +==================== + + 0. Definitions. + + “This License” refers to version 3 of the GNU General Public + License. + + “Copyright” also means copyright-like laws that apply to other + kinds of works, such as semiconductor masks. + + “The Program” refers to any copyrightable work licensed under this + License. Each licensee is addressed as “you”. “Licensees” and + “recipients” may be individuals or organizations. + + To “modify” a work means to copy from or adapt all or part of the + work in a fashion requiring copyright permission, other than the + making of an exact copy. The resulting work is called a “modified + version” of the earlier work or a work “based on” the earlier work. + + A “covered work” means either the unmodified Program or a work + based on the Program. + + To “propagate” a work means to do anything with it that, without + permission, would make you directly or secondarily liable for + infringement under applicable copyright law, except executing it on + a computer or modifying a private copy. Propagation includes + copying, distribution (with or without modification), making + available to the public, and in some countries other activities as + well. + + To “convey” a work means any kind of propagation that enables other + parties to make or receive copies. Mere interaction with a user + through a computer network, with no transfer of a copy, is not + conveying. + + An interactive user interface displays “Appropriate Legal Notices” + to the extent that it includes a convenient and prominently visible + feature that (1) displays an appropriate copyright notice, and (2) + tells the user that there is no warranty for the work (except to + the extent that warranties are provided), that licensees may convey + the work under this License, and how to view a copy of this + License. If the interface presents a list of user commands or + options, such as a menu, a prominent item in the list meets this + criterion. + + 1. Source Code. + + The “source code” for a work means the preferred form of the work + for making modifications to it. “Object code” means any non-source + form of a work. + + A “Standard Interface” means an interface that either is an + official standard defined by a recognized standards body, or, in + the case of interfaces specified for a particular programming + language, one that is widely used among developers working in that + language. + + The “System Libraries” of an executable work include anything, + other than the work as a whole, that (a) is included in the normal + form of packaging a Major Component, but which is not part of that + Major Component, and (b) serves only to enable use of the work with + that Major Component, or to implement a Standard Interface for + which an implementation is available to the public in source code + form. A “Major Component”, in this context, means a major + essential component (kernel, window system, and so on) of the + specific operating system (if any) on which the executable work + runs, or a compiler used to produce the work, or an object code + interpreter used to run it. + + The “Corresponding Source” for a work in object code form means all + the source code needed to generate, install, and (for an executable + work) run the object code and to modify the work, including scripts + to control those activities. However, it does not include the + work’s System Libraries, or general-purpose tools or generally + available free programs which are used unmodified in performing + those activities but which are not part of the work. For example, + Corresponding Source includes interface definition files associated + with source files for the work, and the source code for shared + libraries and dynamically linked subprograms that the work is + specifically designed to require, such as by intimate data + communication or control flow between those subprograms and other + parts of the work. + + The Corresponding Source need not include anything that users can + regenerate automatically from other parts of the Corresponding + Source. + + The Corresponding Source for a work in source code form is that + same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of + copyright on the Program, and are irrevocable provided the stated + conditions are met. This License explicitly affirms your unlimited + permission to run the unmodified Program. The output from running + a covered work is covered by this License only if the output, given + its content, constitutes a covered work. This License acknowledges + your rights of fair use or other equivalent, as provided by + copyright law. + + You may make, run and propagate covered works that you do not + convey, without conditions so long as your license otherwise + remains in force. You may convey covered works to others for the + sole purpose of having them make modifications exclusively for you, + or provide you with facilities for running those works, provided + that you comply with the terms of this License in conveying all + material for which you do not control copyright. Those thus making + or running the covered works for you must do so exclusively on your + behalf, under your direction and control, on terms that prohibit + them from making any copies of your copyrighted material outside + their relationship with you. + + Conveying under any other circumstances is permitted solely under + the conditions stated below. Sublicensing is not allowed; section + 10 makes it unnecessary. + + 3. Protecting Users’ Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological + measure under any applicable law fulfilling obligations under + article 11 of the WIPO copyright treaty adopted on 20 December + 1996, or similar laws prohibiting or restricting circumvention of + such measures. + + When you convey a covered work, you waive any legal power to forbid + circumvention of technological measures to the extent such + circumvention is effected by exercising rights under this License + with respect to the covered work, and you disclaim any intention to + limit operation or modification of the work as a means of + enforcing, against the work’s users, your or third parties’ legal + rights to forbid circumvention of technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program’s source code as you + receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice; + keep intact all notices stating that this License and any + non-permissive terms added in accord with section 7 apply to the + code; keep intact all notices of the absence of any warranty; and + give all recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, + and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to + produce it from the Program, in the form of source code under the + terms of section 4, provided that you also meet all of these + conditions: + + a. The work must carry prominent notices stating that you + modified it, and giving a relevant date. + + b. The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in + section 4 to “keep intact all notices”. + + c. You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable + section 7 additional terms, to the whole of the work, and all + its parts, regardless of how they are packaged. This License + gives no permission to license the work in any other way, but + it does not invalidate such permission if you have separately + received it. + + d. If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has + interactive interfaces that do not display Appropriate Legal + Notices, your work need not make them do so. + + A compilation of a covered work with other separate and independent + works, which are not by their nature extensions of the covered + work, and which are not combined with it such as to form a larger + program, in or on a volume of a storage or distribution medium, is + called an “aggregate” if the compilation and its resulting + copyright are not used to limit the access or legal rights of the + compilation’s users beyond what the individual works permit. + Inclusion of a covered work in an aggregate does not cause this + License to apply to the other parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms + of sections 4 and 5, provided that you also convey the + machine-readable Corresponding Source under the terms of this + License, in one of these ways: + + a. Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b. Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that + product model, to give anyone who possesses the object code + either (1) a copy of the Corresponding Source for all the + software in the product that is covered by this License, on a + durable physical medium customarily used for software + interchange, for a price no more than your reasonable cost of + physically performing this conveying of source, or (2) access + to copy the Corresponding Source from a network server at no + charge. + + c. Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, + and only if you received the object code with such an offer, + in accord with subsection 6b. + + d. Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to + the Corresponding Source in the same way through the same + place at no further charge. You need not require recipients + to copy the Corresponding Source along with the object code. + If the place to copy the object code is a network server, the + Corresponding Source may be on a different server (operated by + you or a third party) that supports equivalent copying + facilities, provided you maintain clear directions next to the + object code saying where to find the Corresponding Source. + Regardless of what server hosts the Corresponding Source, you + remain obligated to ensure that it is available for as long as + needed to satisfy these requirements. + + e. Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the + general public at no charge under subsection 6d. + + A separable portion of the object code, whose source code is + excluded from the Corresponding Source as a System Library, need + not be included in conveying the object code work. + + A “User Product” is either (1) a “consumer product”, which means + any tangible personal property which is normally used for personal, + family, or household purposes, or (2) anything designed or sold for + incorporation into a dwelling. In determining whether a product is + a consumer product, doubtful cases shall be resolved in favor of + coverage. For a particular product received by a particular user, + “normally used” refers to a typical or common use of that class of + product, regardless of the status of the particular user or of the + way in which the particular user actually uses, or expects or is + expected to use, the product. A product is a consumer product + regardless of whether the product has substantial commercial, + industrial or non-consumer uses, unless such uses represent the + only significant mode of use of the product. + + “Installation Information” for a User Product means any methods, + procedures, authorization keys, or other information required to + install and execute modified versions of a covered work in that + User Product from a modified version of its Corresponding Source. + The information must suffice to ensure that the continued + functioning of the modified object code is in no case prevented or + interfered with solely because modification has been made. + + If you convey an object code work under this section in, or with, + or specifically for use in, a User Product, and the conveying + occurs as part of a transaction in which the right of possession + and use of the User Product is transferred to the recipient in + perpetuity or for a fixed term (regardless of how the transaction + is characterized), the Corresponding Source conveyed under this + section must be accompanied by the Installation Information. But + this requirement does not apply if neither you nor any third party + retains the ability to install modified object code on the User + Product (for example, the work has been installed in ROM). + + The requirement to provide Installation Information does not + include a requirement to continue to provide support service, + warranty, or updates for a work that has been modified or installed + by the recipient, or for the User Product in which it has been + modified or installed. Access to a network may be denied when the + modification itself materially and adversely affects the operation + of the network or violates the rules and protocols for + communication across the network. + + Corresponding Source conveyed, and Installation Information + provided, in accord with this section must be in a format that is + publicly documented (and with an implementation available to the + public in source code form), and must require no special password + or key for unpacking, reading or copying. + + 7. Additional Terms. + + “Additional permissions” are terms that supplement the terms of + this License by making exceptions from one or more of its + conditions. Additional permissions that are applicable to the + entire Program shall be treated as though they were included in + this License, to the extent that they are valid under applicable + law. If additional permissions apply only to part of the Program, + that part may be used separately under those permissions, but the + entire Program remains governed by this License without regard to + the additional permissions. + + When you convey a copy of a covered work, you may at your option + remove any additional permissions from that copy, or from any part + of it. (Additional permissions may be written to require their own + removal in certain cases when you modify the work.) You may place + additional permissions on material, added by you to a covered work, + for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material + you add to a covered work, you may (if authorized by the copyright + holders of that material) supplement the terms of this License with + terms: + + a. Disclaiming warranty or limiting liability differently from + the terms of sections 15 and 16 of this License; or + + b. Requiring preservation of specified reasonable legal notices + or author attributions in that material or in the Appropriate + Legal Notices displayed by works containing it; or + + c. Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked + in reasonable ways as different from the original version; or + + d. Limiting the use for publicity purposes of names of licensors + or authors of the material; or + + e. Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f. Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified + versions of it) with contractual assumptions of liability to + the recipient, for any liability that these contractual + assumptions directly impose on those licensors and authors. + + All other non-permissive additional terms are considered “further + restrictions” within the meaning of section 10. If the Program as + you received it, or any part of it, contains a notice stating that + it is governed by this License along with a term that is a further + restriction, you may remove that term. If a license document + contains a further restriction but permits relicensing or conveying + under this License, you may add to a covered work material governed + by the terms of that license document, provided that the further + restriction does not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you + must place, in the relevant source files, a statement of the + additional terms that apply to those files, or a notice indicating + where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in + the form of a separately written license, or stated as exceptions; + the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly + provided under this License. Any attempt otherwise to propagate or + modify it is void, and will automatically terminate your rights + under this License (including any patent licenses granted under the + third paragraph of section 11). + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from + that copyright holder, and you cure the violation prior to 30 days + after your receipt of the notice. + + Termination of your rights under this section does not terminate + the licenses of parties who have received copies or rights from you + under this License. If your rights have been terminated and not + permanently reinstated, you do not qualify to receive new licenses + for the same material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or + run a copy of the Program. Ancillary propagation of a covered work + occurring solely as a consequence of using peer-to-peer + transmission to receive a copy likewise does not require + acceptance. However, nothing other than this License grants you + permission to propagate or modify any covered work. These actions + infringe copyright if you do not accept this License. Therefore, + by modifying or propagating a covered work, you indicate your + acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically + receives a license from the original licensors, to run, modify and + propagate that work, subject to this License. You are not + responsible for enforcing compliance by third parties with this + License. + + An “entity transaction” is a transaction transferring control of an + organization, or substantially all assets of one, or subdividing an + organization, or merging organizations. If propagation of a + covered work results from an entity transaction, each party to that + transaction who receives a copy of the work also receives whatever + licenses to the work the party’s predecessor in interest had or + could give under the previous paragraph, plus a right to possession + of the Corresponding Source of the work from the predecessor in + interest, if the predecessor has it or can get it with reasonable + efforts. + + You may not impose any further restrictions on the exercise of the + rights granted or affirmed under this License. For example, you + may not impose a license fee, royalty, or other charge for exercise + of rights granted under this License, and you may not initiate + litigation (including a cross-claim or counterclaim in a lawsuit) + alleging that any patent claim is infringed by making, using, + selling, offering for sale, or importing the Program or any portion + of it. + + 11. Patents. + + A “contributor” is a copyright holder who authorizes use under this + License of the Program or a work on which the Program is based. + The work thus licensed is called the contributor’s “contributor + version”. + + A contributor’s “essential patent claims” are all patent claims + owned or controlled by the contributor, whether already acquired or + hereafter acquired, that would be infringed by some manner, + permitted by this License, of making, using, or selling its + contributor version, but do not include claims that would be + infringed only as a consequence of further modification of the + contributor version. For purposes of this definition, “control” + includes the right to grant patent sublicenses in a manner + consistent with the requirements of this License. + + Each contributor grants you a non-exclusive, worldwide, + royalty-free patent license under the contributor’s essential + patent claims, to make, use, sell, offer for sale, import and + otherwise run, modify and propagate the contents of its contributor + version. + + In the following three paragraphs, a “patent license” is any + express agreement or commitment, however denominated, not to + enforce a patent (such as an express permission to practice a + patent or covenant not to sue for patent infringement). To “grant” + such a patent license to a party means to make such an agreement or + commitment not to enforce a patent against the party. + + If you convey a covered work, knowingly relying on a patent + license, and the Corresponding Source of the work is not available + for anyone to copy, free of charge and under the terms of this + License, through a publicly available network server or other + readily accessible means, then you must either (1) cause the + Corresponding Source to be so available, or (2) arrange to deprive + yourself of the benefit of the patent license for this particular + work, or (3) arrange, in a manner consistent with the requirements + of this License, to extend the patent license to downstream + recipients. “Knowingly relying” means you have actual knowledge + that, but for the patent license, your conveying the covered work + in a country, or your recipient’s use of the covered work in a + country, would infringe one or more identifiable patents in that + country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or + arrangement, you convey, or propagate by procuring conveyance of, a + covered work, and grant a patent license to some of the parties + receiving the covered work authorizing them to use, propagate, + modify or convey a specific copy of the covered work, then the + patent license you grant is automatically extended to all + recipients of the covered work and works based on it. + + A patent license is “discriminatory” if it does not include within + the scope of its coverage, prohibits the exercise of, or is + conditioned on the non-exercise of one or more of the rights that + are specifically granted under this License. You may not convey a + covered work if you are a party to an arrangement with a third + party that is in the business of distributing software, under which + you make payment to the third party based on the extent of your + activity of conveying the work, and under which the third party + grants, to any of the parties who would receive the covered work + from you, a discriminatory patent license (a) in connection with + copies of the covered work conveyed by you (or copies made from + those copies), or (b) primarily for and in connection with specific + products or compilations that contain the covered work, unless you + entered into that arrangement, or that patent license was granted, + prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting + any implied license or other defenses to infringement that may + otherwise be available to you under applicable patent law. + + 12. No Surrender of Others’ Freedom. + + If conditions are imposed on you (whether by court order, agreement + or otherwise) that contradict the conditions of this License, they + do not excuse you from the conditions of this License. If you + cannot convey a covered work so as to satisfy simultaneously your + obligations under this License and any other pertinent obligations, + then as a consequence you may not convey it at all. For example, + if you agree to terms that obligate you to collect a royalty for + further conveying from those to whom you convey the Program, the + only way you could satisfy both those terms and this License would + be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have + permission to link or combine any covered work with a work licensed + under version 3 of the GNU Affero General Public License into a + single combined work, and to convey the resulting work. The terms + of this License will continue to apply to the part which is the + covered work, but the special requirements of the GNU Affero + General Public License, section 13, concerning interaction through + a network will apply to the combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new + versions of the GNU General Public License from time to time. Such + new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies that a certain numbered version of the GNU + General Public License “or any later version” applies to it, you + have the option of following the terms and conditions either of + that numbered version or of any later version published by the Free + Software Foundation. If the Program does not specify a version + number of the GNU General Public License, you may choose any + version ever published by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future + versions of the GNU General Public License can be used, that + proxy’s public statement of acceptance of a version permanently + authorizes you to choose that version for the Program. + + Later license versions may give you additional or different + permissions. However, no additional obligations are imposed on any + author or copyright holder as a result of your choosing to follow a + later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY + APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE + COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE + RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. + SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES + AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE + THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA + BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD + PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF + THE POSSIBILITY OF SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided + above cannot be given local legal effect according to their terms, + reviewing courts shall apply local law that most closely + approximates an absolute waiver of all civil liability in + connection with the Program, unless a warranty or assumption of + liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS +=========================== + +How to Apply These Terms to Your New Programs +============================================= + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least the +“copyright” line and a pointer to where the full notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. + Copyright (C) YEAR NAME OF AUTHOR + + 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 . + + Also add information on how to contact you by electronic and paper +mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + PROGRAM Copyright (C) YEAR NAME OF AUTHOR + This program comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’. + This is free software, and you are welcome to redistribute it + under certain conditions; type ‘show c’ for details. + + The hypothetical commands ‘show w’ and ‘show c’ should show the +appropriate parts of the General Public License. Of course, your +program’s commands might be different; for a GUI interface, you would +use an “about box”. + + You should also get your employer (if you work as a programmer) or +school, if any, to sign a “copyright disclaimer” for the program, if +necessary. For more information on this, and how to apply and follow +the GNU GPL, see . + + The GNU General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Lesser General Public License instead of this License. But first, +please read . + + +File: dash.info, Node: Index, Prev: GPL, Up: Top + +Index +***** + +[index] +* Menu: + +* !cdr: Destructive operations. + (line 16) +* !cons: Destructive operations. + (line 8) +* -->: Threading macros. (line 35) +* ->: Threading macros. (line 9) +* ->>: Threading macros. (line 22) +* -all?: Predicates. (line 53) +* -andfn: Function combinators. + (line 184) +* -annotate: Maps. (line 86) +* -any?: Predicates. (line 41) +* -applify: Function combinators. + (line 63) +* -as->: Threading macros. (line 49) +* -butlast: Other list operations. + (line 405) +* -clone: Tree operations. (line 123) +* -common-prefix: Reductions. (line 242) +* -common-suffix: Reductions. (line 252) +* -compose: Function combinators. + (line 49) +* -concat: List to list. (line 23) +* -cons*: Other list operations. + (line 19) +* -cons-pair?: Predicates. (line 154) +* -const: Function combinators. + (line 128) +* -contains?: Predicates. (line 100) +* -copy: Maps. (line 151) +* -count: Reductions. (line 172) +* -cut: Function combinators. + (line 140) +* -cycle: Unfolding. (line 55) +* -difference: Set operations. (line 22) +* -distinct: Set operations. (line 73) +* -dotimes: Side effects. (line 80) +* -doto: Threading macros. (line 99) +* -drop: Sublist selection. (line 149) +* -drop-last: Sublist selection. (line 163) +* -drop-while: Sublist selection. (line 194) +* -each: Side effects. (line 8) +* -each-indexed: Side effects. (line 38) +* -each-r: Side effects. (line 52) +* -each-r-while: Side effects. (line 65) +* -each-while: Side effects. (line 24) +* -elem-index: Indexing. (line 9) +* -elem-indices: Indexing. (line 23) +* -every: Predicates. (line 23) +* -fifth-item: Other list operations. + (line 380) +* -filter: Sublist selection. (line 8) +* -find-index: Indexing. (line 35) +* -find-indices: Indexing. (line 73) +* -find-last-index: Indexing. (line 54) +* -first: Other list operations. + (line 300) +* -first-item: Other list operations. + (line 328) +* -fix: Other list operations. + (line 445) +* -fixfn: Function combinators. + (line 224) +* -flatten: List to list. (line 38) +* -flatten-n: List to list. (line 60) +* -flip: Function combinators. + (line 95) +* -fourth-item: Other list operations. + (line 367) +* -frequencies: Reductions. (line 310) +* -grade-down: Indexing. (line 103) +* -grade-up: Indexing. (line 93) +* -group-by: Partitioning. (line 205) +* -if-let: Binding. (line 34) +* -if-let*: Binding. (line 45) +* -inits: Reductions. (line 222) +* -insert-at: List to list. (line 114) +* -interleave: Other list operations. + (line 56) +* -interpose: Other list operations. + (line 46) +* -intersection: Set operations. (line 36) +* -iota: Other list operations. + (line 67) +* -is-infix?: Predicates. (line 140) +* -is-prefix?: Predicates. (line 116) +* -is-suffix?: Predicates. (line 128) +* -iterate: Unfolding. (line 9) +* -iteratefn: Function combinators. + (line 201) +* -juxt: Function combinators. + (line 37) +* -keep: List to list. (line 8) +* -lambda: Binding. (line 247) +* -last: Other list operations. + (line 318) +* -last-item: Other list operations. + (line 393) +* -let: Binding. (line 61) +* -let*: Binding. (line 227) +* -list: Other list operations. + (line 428) +* -map: Maps. (line 10) +* -map-first: Maps. (line 38) +* -map-indexed: Maps. (line 68) +* -map-last: Maps. (line 53) +* -map-when: Maps. (line 22) +* -mapcat: Maps. (line 140) +* -max: Reductions. (line 286) +* -max-by: Reductions. (line 296) +* -min: Reductions. (line 262) +* -min-by: Reductions. (line 272) +* -non-nil: Sublist selection. (line 95) +* -none?: Predicates. (line 73) +* -not: Function combinators. + (line 153) +* -on: Function combinators. + (line 75) +* -only-some?: Predicates. (line 85) +* -orfn: Function combinators. + (line 167) +* -pad: Other list operations. + (line 241) +* -partial: Function combinators. + (line 8) +* -partition: Partitioning. (line 90) +* -partition-after-item: Partitioning. (line 195) +* -partition-after-pred: Partitioning. (line 162) +* -partition-all: Partitioning. (line 102) +* -partition-all-in-steps: Partitioning. (line 126) +* -partition-before-item: Partitioning. (line 185) +* -partition-before-pred: Partitioning. (line 174) +* -partition-by: Partitioning. (line 138) +* -partition-by-header: Partitioning. (line 149) +* -partition-in-steps: Partitioning. (line 113) +* -permutations: Set operations. (line 60) +* -powerset: Set operations. (line 50) +* -prodfn: Function combinators. + (line 258) +* -product: Reductions. (line 201) +* -reduce: Reductions. (line 53) +* -reduce-from: Reductions. (line 8) +* -reduce-r: Reductions. (line 72) +* -reduce-r-from: Reductions. (line 26) +* -reductions: Reductions. (line 136) +* -reductions-from: Reductions. (line 100) +* -reductions-r: Reductions. (line 154) +* -reductions-r-from: Reductions. (line 118) +* -remove: Sublist selection. (line 26) +* -remove-at: List to list. (line 151) +* -remove-at-indices: List to list. (line 170) +* -remove-first: Sublist selection. (line 44) +* -remove-item: Sublist selection. (line 84) +* -remove-last: Sublist selection. (line 65) +* -repeat: Unfolding. (line 44) +* -replace: List to list. (line 72) +* -replace-at: List to list. (line 125) +* -replace-first: List to list. (line 86) +* -replace-last: List to list. (line 100) +* -rotate: Other list operations. + (line 8) +* -rotate-args: Function combinators. + (line 112) +* -rpartial: Function combinators. + (line 22) +* -running-product: Reductions. (line 211) +* -running-sum: Reductions. (line 190) +* -same-items?: Set operations. (line 88) +* -second-item: Other list operations. + (line 341) +* -select-by-indices: Sublist selection. (line 211) +* -select-column: Sublist selection. (line 241) +* -select-columns: Sublist selection. (line 222) +* -separate: Partitioning. (line 75) +* -setq: Binding. (line 270) +* -slice: Sublist selection. (line 105) +* -snoc: Other list operations. + (line 32) +* -some: Predicates. (line 8) +* -some-->: Threading macros. (line 86) +* -some->: Threading macros. (line 62) +* -some->>: Threading macros. (line 74) +* -sort: Other list operations. + (line 415) +* -splice: Maps. (line 102) +* -splice-list: Maps. (line 127) +* -split-at: Partitioning. (line 8) +* -split-on: Partitioning. (line 40) +* -split-when: Partitioning. (line 58) +* -split-with: Partitioning. (line 23) +* -sum: Reductions. (line 180) +* -table: Other list operations. + (line 256) +* -table-flat: Other list operations. + (line 275) +* -tails: Reductions. (line 232) +* -take: Sublist selection. (line 121) +* -take-last: Sublist selection. (line 135) +* -take-while: Sublist selection. (line 177) +* -third-item: Other list operations. + (line 354) +* -tree-map: Tree operations. (line 28) +* -tree-map-nodes: Tree operations. (line 39) +* -tree-mapreduce: Tree operations. (line 85) +* -tree-mapreduce-from: Tree operations. (line 104) +* -tree-reduce: Tree operations. (line 53) +* -tree-reduce-from: Tree operations. (line 70) +* -tree-seq: Tree operations. (line 8) +* -unfold: Unfolding. (line 25) +* -union: Set operations. (line 8) +* -unzip: Other list operations. + (line 215) +* -unzip-lists: Other list operations. + (line 196) +* -update-at: List to list. (line 137) +* -when-let: Binding. (line 9) +* -when-let*: Binding. (line 21) +* -zip: Other list operations. + (line 150) +* -zip-fill: Other list operations. + (line 176) +* -zip-lists: Other list operations. + (line 114) +* -zip-lists-fill: Other list operations. + (line 135) +* -zip-pair: Other list operations. + (line 98) +* -zip-with: Other list operations. + (line 80) +* dash-fontify-mode: Fontification of special variables. + (line 6) +* dash-register-info-lookup: Info symbol lookup. (line 6) +* global-dash-fontify-mode: Fontification of special variables. + (line 12) + + + +Tag Table: +Node: Top742 +Node: Installation2397 +Node: Using in a package3159 +Node: Fontification of special variables3504 +Node: Info symbol lookup4294 +Node: Functions4877 +Node: Maps6361 +Ref: -map6658 +Ref: -map-when7031 +Ref: -map-first7605 +Ref: -map-last8200 +Ref: -map-indexed8790 +Ref: -annotate9476 +Ref: -splice10080 +Ref: -splice-list11155 +Ref: -mapcat11614 +Ref: -copy11987 +Node: Sublist selection12175 +Ref: -filter12368 +Ref: -remove12921 +Ref: -remove-first13470 +Ref: -remove-last14318 +Ref: -remove-item15048 +Ref: -non-nil15448 +Ref: -slice15730 +Ref: -take16259 +Ref: -take-last16677 +Ref: -drop17114 +Ref: -drop-last17561 +Ref: -take-while17993 +Ref: -drop-while18620 +Ref: -select-by-indices19253 +Ref: -select-columns19764 +Ref: -select-column20467 +Node: List to list20930 +Ref: -keep21122 +Ref: -concat21698 +Ref: -flatten22226 +Ref: -flatten-n22988 +Ref: -replace23372 +Ref: -replace-first23833 +Ref: -replace-last24328 +Ref: -insert-at24816 +Ref: -replace-at25141 +Ref: -update-at25528 +Ref: -remove-at26069 +Ref: -remove-at-indices26696 +Node: Reductions27386 +Ref: -reduce-from27582 +Ref: -reduce-r-from28306 +Ref: -reduce29569 +Ref: -reduce-r30320 +Ref: -reductions-from31598 +Ref: -reductions-r-from32404 +Ref: -reductions33234 +Ref: -reductions-r33945 +Ref: -count34690 +Ref: -sum34920 +Ref: -running-sum35108 +Ref: -product35429 +Ref: -running-product35637 +Ref: -inits35978 +Ref: -tails36223 +Ref: -common-prefix36468 +Ref: -common-suffix36762 +Ref: -min37056 +Ref: -min-by37282 +Ref: -max37803 +Ref: -max-by38028 +Ref: -frequencies38554 +Node: Unfolding39169 +Ref: -iterate39410 +Ref: -unfold39857 +Ref: -repeat40662 +Ref: -cycle40946 +Node: Predicates41343 +Ref: -some41520 +Ref: -every41949 +Ref: -any?42663 +Ref: -all?43012 +Ref: -none?43754 +Ref: -only-some?44074 +Ref: -contains?44619 +Ref: -is-prefix?45125 +Ref: -is-suffix?45457 +Ref: -is-infix?45789 +Ref: -cons-pair?46149 +Node: Partitioning46480 +Ref: -split-at46668 +Ref: -split-with47332 +Ref: -split-on47972 +Ref: -split-when48643 +Ref: -separate49286 +Ref: -partition49820 +Ref: -partition-all50269 +Ref: -partition-in-steps50694 +Ref: -partition-all-in-steps51240 +Ref: -partition-by51754 +Ref: -partition-by-header52132 +Ref: -partition-after-pred52733 +Ref: -partition-before-pred53186 +Ref: -partition-before-item53571 +Ref: -partition-after-item53878 +Ref: -group-by54180 +Node: Indexing54613 +Ref: -elem-index54815 +Ref: -elem-indices55302 +Ref: -find-index55761 +Ref: -find-last-index56430 +Ref: -find-indices57081 +Ref: -grade-up57843 +Ref: -grade-down58250 +Node: Set operations58664 +Ref: -union58847 +Ref: -difference59277 +Ref: -intersection59705 +Ref: -powerset60134 +Ref: -permutations60411 +Ref: -distinct60849 +Ref: -same-items?61243 +Node: Other list operations61852 +Ref: -rotate62077 +Ref: -cons*62430 +Ref: -snoc62852 +Ref: -interpose63264 +Ref: -interleave63558 +Ref: -iota63924 +Ref: -zip-with64407 +Ref: -zip-pair65215 +Ref: -zip-lists65781 +Ref: -zip-lists-fill66579 +Ref: -zip67289 +Ref: -zip-fill68316 +Ref: -unzip-lists69230 +Ref: -unzip69853 +Ref: -pad70846 +Ref: -table71331 +Ref: -table-flat72117 +Ref: -first73122 +Ref: -last73655 +Ref: -first-item74001 +Ref: -second-item74413 +Ref: -third-item74830 +Ref: -fourth-item75205 +Ref: -fifth-item75583 +Ref: -last-item75958 +Ref: -butlast76319 +Ref: -sort76564 +Ref: -list77058 +Ref: -fix77627 +Node: Tree operations78116 +Ref: -tree-seq78312 +Ref: -tree-map79173 +Ref: -tree-map-nodes79613 +Ref: -tree-reduce80477 +Ref: -tree-reduce-from81359 +Ref: -tree-mapreduce81959 +Ref: -tree-mapreduce-from82818 +Ref: -clone84103 +Node: Threading macros84441 +Ref: ->84666 +Ref: ->>85154 +Ref: -->85657 +Ref: -as->86214 +Ref: -some->86668 +Ref: -some->>87053 +Ref: -some-->87500 +Ref: -doto88067 +Node: Binding88620 +Ref: -when-let88827 +Ref: -when-let*89288 +Ref: -if-let89817 +Ref: -if-let*90183 +Ref: -let90806 +Ref: -let*96896 +Ref: -lambda97833 +Ref: -setq98639 +Node: Side effects99440 +Ref: -each99634 +Ref: -each-while100161 +Ref: -each-indexed100781 +Ref: -each-r101373 +Ref: -each-r-while101815 +Ref: -dotimes102459 +Node: Destructive operations103012 +Ref: !cons103230 +Ref: !cdr103434 +Node: Function combinators103627 +Ref: -partial103831 +Ref: -rpartial104349 +Ref: -juxt104997 +Ref: -compose105449 +Ref: -applify106056 +Ref: -on106486 +Ref: -flip107258 +Ref: -rotate-args107782 +Ref: -const108411 +Ref: -cut108753 +Ref: -not109233 +Ref: -orfn109777 +Ref: -andfn110570 +Ref: -iteratefn111357 +Ref: -fixfn112059 +Ref: -prodfn113633 +Node: Development114784 +Node: Contribute115073 +Node: Contributors116085 +Node: FDL118178 +Node: GPL143498 +Node: Index181247 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/elpa/dash-20240510.1327/dir b/elpa/dash-20240510.1327/dir new file mode 100644 index 00000000..7d473f49 --- /dev/null +++ b/elpa/dash-20240510.1327/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" 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. diff --git a/elpa/dash-readme.txt b/elpa/dash-readme.txt deleted file mode 100644 index b6baaa2d..00000000 --- a/elpa/dash-readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -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.