(if (>= emacs-major-version 24)
(progn
(add-to-list 'load-path "~/.emacs.d/elpa/smartparens-20200105.1259")
- (add-to-list 'load-path "~/.emacs.d/elpa/dash-20200119.2310")
+ (add-to-list 'load-path "~/.emacs.d/elpa/dash-20210101.1712")
(require 'smartparens)
(smartparens-global-mode 1)
(defmacro def-pairs (pairs)
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
- '(org-block ((t (:inherit shadow :background "#29759c" :foreground "#84cbef" :distant-forground "#131313"))))
- '(org-block-begin-line ((t (:background "#07538a" :foreground "#84cbef"))))
+ '(org-block ((t (:inherit shadow :background "#29759c" :foreground "#84cbef" :distant-forground "#131313" :extend t))))
+ '(org-block-begin-line ((t (:background "#07538a" :foreground "#84cbef" :extend t))))
'(org-block-end-line ((t (:inherit org-block-begin-line))))
'(org-document-title ((t (:inherit default :foreground "#62a9cd" :font "Arial" :height 1.5 :underline nil))))
'(org-level-1 ((t (:inherit default :foreground "#62a9cd" :font "Arial" :height 1.6))))
+++ /dev/null
-;;; dash-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-
-(add-to-list 'load-path (directory-file-name
- (or (file-name-directory #$) (car load-path))))
-
-\f
-;;;### (autoloads nil "dash" "dash.el" (0 0 0 0))
-;;; Generated autoloads from dash.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dash" '("dash-" "-keep" "-butlast" "-non" "-only-some" "-zip" "-e" "->" "-a" "-gr" "-when-let" "-d" "-l" "-s" "-p" "-r" "-m" "-i" "-f" "-u" "-value-to-list" "-t" "--" "-c" "!cons" "!cdr")))
-
-;;;***
-\f
-;;;### (autoloads nil nil ("dash-pkg.el") (0 0 0 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; coding: utf-8
-;; End:
-;;; dash-autoloads.el ends here
+++ /dev/null
-(define-package "dash" "20200119.2310" "A modern list library for Emacs" 'nil :keywords
- '("lists")
- :authors
- '(("Magnar Sveen" . "magnarsNOSPAMgmail.com"))
- :maintainer
- '("Magnar Sveen" . "magnarsNOSPAMgmail.com"))
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
-
-;; Author: Magnar Sveen <magnarsNOSPAMgmail.com>
-;; Version: 2.17.0
-;; Keywords: lists
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; A modern list api for Emacs.
-;;
-;; See documentation on https://github.com/magnars/dash.el#functions
-;;
-;; **Please note** The lexical binding in this file is not utilised at the
-;; moment. We will take full advantage of lexical binding in an upcoming 3.0
-;; release of Dash. In the meantime, we've added the pragma to avoid a bug that
-;; you can read more about in https://github.com/magnars/dash.el/issues/130.
-;;
-
-;;; Code:
-
-;; TODO: `gv' was introduced in Emacs 24.3, so remove this and all
-;; calls to `defsetf' when support for earlier versions is dropped.
-(eval-when-compile
- (unless (fboundp 'gv-define-setter)
- (require 'cl)))
-
-(defgroup dash ()
- "Customize group for dash.el"
- :group 'lisp
- :prefix "dash-")
-
-(defun dash--enable-fontlock (symbol value)
- (when value
- (dash-enable-font-lock))
- (set-default symbol value))
-
-(defcustom dash-enable-fontlock nil
- "If non-nil, enable fontification of dash functions, macros and
-special values."
- :type 'boolean
- :set 'dash--enable-fontlock
- :group 'dash)
-
-(defmacro !cons (car cdr)
- "Destructive: Set CDR to the cons of CAR and CDR."
- `(setq ,cdr (cons ,car ,cdr)))
-
-(defmacro !cdr (list)
- "Destructive: Set LIST to the cdr of LIST."
- `(setq ,list (cdr ,list)))
-
-(defmacro --each (list &rest body)
- "Anaphoric form of `-each'."
- (declare (debug (form body))
- (indent 1))
- (let ((l (make-symbol "list")))
- `(let ((,l ,list)
- (it-index 0))
- (while ,l
- (let ((it (car ,l)))
- ,@body)
- (setq it-index (1+ it-index))
- (!cdr ,l)))))
-
-(defmacro -doto (eval-initial-value &rest forms)
- "Eval a form, then insert that form as the 2nd argument to other forms.
-The EVAL-INITIAL-VALUE form is evaluated once. Its result is
-passed to FORMS, which are then evaluated sequentially. Returns
-the target form."
- (declare (indent 1))
- (let ((retval (make-symbol "value")))
- `(let ((,retval ,eval-initial-value))
- ,@(mapcar (lambda (form)
- (if (sequencep form)
- `(,(-first-item form) ,retval ,@(cdr form))
- `(funcall form ,retval)))
- forms)
- ,retval)))
-
-(defmacro --doto (eval-initial-value &rest forms)
- "Anaphoric form of `-doto'.
-Note: `it' is not required in each form."
- (declare (indent 1))
- `(let ((it ,eval-initial-value))
- ,@forms
- it))
-
-(defun -each (list fn)
- "Call FN with every item in LIST. Return nil, used for side-effects only."
- (--each list (funcall fn it)))
-
-(put '-each 'lisp-indent-function 1)
-
-(defalias '--each-indexed '--each)
-
-(defun -each-indexed (list fn)
- "Call (FN index item) for each item in LIST.
-
-In the anaphoric form `--each-indexed', the index is exposed as symbol `it-index'.
-
-See also: `-map-indexed'."
- (--each list (funcall fn it-index it)))
-(put '-each-indexed 'lisp-indent-function 1)
-
-(defmacro --each-while (list pred &rest body)
- "Anaphoric form of `-each-while'."
- (declare (debug (form form body))
- (indent 2))
- (let ((l (make-symbol "list"))
- (c (make-symbol "continue")))
- `(let ((,l ,list)
- (,c t)
- (it-index 0))
- (while (and ,l ,c)
- (let ((it (car ,l)))
- (if (not ,pred) (setq ,c nil) ,@body))
- (setq it-index (1+ it-index))
- (!cdr ,l)))))
-
-(defun -each-while (list pred fn)
- "Call FN with every item in LIST while (PRED item) is non-nil.
-Return nil, used for side-effects only."
- (--each-while list (funcall pred it) (funcall fn it)))
-
-(put '-each-while 'lisp-indent-function 2)
-
-(defmacro --each-r (list &rest body)
- "Anaphoric form of `-each-r'."
- (declare (debug (form body))
- (indent 1))
- (let ((v (make-symbol "vector")))
- ;; Implementation note: building vector is considerably faster
- ;; than building a reversed list (vector takes less memory, so
- ;; there is less GC), plus length comes naturally. In-place
- ;; 'nreverse' would be faster still, but BODY would be able to see
- ;; that, even if modification was reversed before we return.
- `(let* ((,v (vconcat ,list))
- (it-index (length ,v))
- it)
- (while (> it-index 0)
- (setq it-index (1- it-index))
- (setq it (aref ,v it-index))
- ,@body))))
-
-(defun -each-r (list fn)
- "Call FN with every item in LIST in reversed order.
- Return nil, used for side-effects only."
- (--each-r list (funcall fn it)))
-
-(defmacro --each-r-while (list pred &rest body)
- "Anaphoric form of `-each-r-while'."
- (declare (debug (form form body))
- (indent 2))
- (let ((v (make-symbol "vector")))
- `(let* ((,v (vconcat ,list))
- (it-index (length ,v))
- it)
- (while (> it-index 0)
- (setq it-index (1- it-index))
- (setq it (aref ,v it-index))
- (if (not ,pred)
- (setq it-index -1)
- ,@body)))))
-
-(defun -each-r-while (list pred fn)
- "Call FN with every item in reversed LIST while (PRED item) is non-nil.
-Return nil, used for side-effects only."
- (--each-r-while list (funcall pred it) (funcall fn it)))
-
-(defmacro --dotimes (num &rest body)
- "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1."
- (declare (debug (form body))
- (indent 1))
- (let ((n (make-symbol "num")))
- `(let ((,n ,num)
- (it 0))
- (while (< it ,n)
- ,@body
- (setq it (1+ it))))))
-
-(defun -dotimes (num fn)
- "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1."
- (--dotimes num (funcall fn it)))
-
-(put '-dotimes 'lisp-indent-function 1)
-
-(defun -map (fn list)
- "Return a new list consisting of the result of applying FN to the items in LIST."
- (mapcar fn list))
-
-(defmacro --map (form list)
- "Anaphoric form of `-map'."
- (declare (debug (form form)))
- `(mapcar (lambda (it) ,form) ,list))
-
-(defmacro --reduce-from (form initial-value list)
- "Anaphoric form of `-reduce-from'."
- (declare (debug (form form form)))
- `(let ((acc ,initial-value))
- (--each ,list (setq acc ,form))
- acc))
-
-(defun -reduce-from (fn initial-value list)
- "Return the result of applying FN to INITIAL-VALUE and the
-first item in LIST, then applying FN to that result and the 2nd
-item, etc. If LIST contains no items, return INITIAL-VALUE and
-do not call FN.
-
-In the anaphoric form `--reduce-from', the accumulated value is
-exposed as symbol `acc'.
-
-See also: `-reduce', `-reduce-r'"
- (--reduce-from (funcall fn acc it) initial-value list))
-
-(defmacro --reduce (form list)
- "Anaphoric form of `-reduce'."
- (declare (debug (form form)))
- (let ((lv (make-symbol "list-value")))
- `(let ((,lv ,list))
- (if ,lv
- (--reduce-from ,form (car ,lv) (cdr ,lv))
- (let (acc it) ,form)))))
-
-(defun -reduce (fn list)
- "Return the result of applying FN to the first 2 items in LIST,
-then applying FN to that result and the 3rd item, etc. If LIST
-contains no items, return the result of calling FN with no
-arguments. If LIST contains a single item, return that item
-and do not call FN.
-
-In the anaphoric form `--reduce', the accumulated value is
-exposed as symbol `acc'.
-
-See also: `-reduce-from', `-reduce-r'"
- (if list
- (-reduce-from fn (car list) (cdr list))
- (funcall fn)))
-
-(defmacro --reduce-r-from (form initial-value list)
- "Anaphoric version of `-reduce-r-from'."
- (declare (debug (form form form)))
- `(--reduce-from ,form ,initial-value (reverse ,list)))
-
-(defun -reduce-r-from (fn initial-value list)
- "Replace conses with FN, nil with INITIAL-VALUE and evaluate
-the resulting expression. If LIST is empty, INITIAL-VALUE is
-returned and FN is not called.
-
-Note: this function works the same as `-reduce-from' but the
-operation associates from right instead of from left.
-
-See also: `-reduce-r', `-reduce'"
- (--reduce-r-from (funcall fn it acc) initial-value list))
-
-(defmacro --reduce-r (form list)
- "Anaphoric version of `-reduce-r'."
- (declare (debug (form form)))
- `(--reduce ,form (reverse ,list)))
-
-(defun -reduce-r (fn list)
- "Replace conses with FN and evaluate the resulting expression.
-The final nil is ignored. If LIST contains no items, return the
-result of calling FN with no arguments. If LIST contains a single
-item, return that item and do not call FN.
-
-The first argument of FN is the new item, the second is the
-accumulated value.
-
-Note: this function works the same as `-reduce' but the operation
-associates from right instead of from left.
-
-See also: `-reduce-r-from', `-reduce'"
- (if list
- (--reduce-r (funcall fn it acc) list)
- (funcall fn)))
-
-(defun -reductions-from (fn init list)
- "Return a list of the intermediate values of the reduction.
-
-See `-reduce-from' for explanation of the arguments.
-
-See also: `-reductions', `-reductions-r', `-reduce-r'"
- (nreverse (--reduce-from (cons (funcall fn (car acc) it) acc) (list init) list)))
-
-(defun -reductions (fn list)
- "Return a list of the intermediate values of the reduction.
-
-See `-reduce' for explanation of the arguments.
-
-See also: `-reductions-from', `-reductions-r', `-reduce-r'"
- (and list (-reductions-from fn (car list) (cdr list))))
-
-(defun -reductions-r-from (fn init list)
- "Return a list of the intermediate values of the reduction.
-
-See `-reduce-r-from' for explanation of the arguments.
-
-See also: `-reductions-r', `-reductions', `-reduce'"
- (--reduce-r-from (cons (funcall fn it (car acc)) acc) (list init) list))
-
-(defun -reductions-r (fn list)
- "Return a list of the intermediate values of the reduction.
-
-See `-reduce-r' for explanation of the arguments.
-
-See also: `-reductions-r-from', `-reductions', `-reduce'"
- (when list
- (let ((rev (reverse list)))
- (--reduce-from (cons (funcall fn it (car acc)) acc)
- (list (car rev))
- (cdr rev)))))
-
-(defmacro --filter (form list)
- "Anaphoric form of `-filter'.
-
-See also: `--remove'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each ,list (when ,form (!cons it ,r)))
- (nreverse ,r))))
-
-(defun -filter (pred list)
- "Return a new list of the items in LIST for which PRED returns a non-nil value.
-
-Alias: `-select'
-
-See also: `-keep', `-remove'."
- (--filter (funcall pred it) list))
-
-(defalias '-select '-filter)
-(defalias '--select '--filter)
-
-(defmacro --remove (form list)
- "Anaphoric form of `-remove'.
-
-See also `--filter'."
- (declare (debug (form form)))
- `(--filter (not ,form) ,list))
-
-(defun -remove (pred list)
- "Return a new list of the items in LIST for which PRED returns nil.
-
-Alias: `-reject'
-
-See also: `-filter'."
- (--remove (funcall pred it) list))
-
-(defalias '-reject '-remove)
-(defalias '--reject '--remove)
-
-(defun -remove-first (pred list)
- "Return a new list with the first item matching PRED removed.
-
-Alias: `-reject-first'
-
-See also: `-remove', `-map-first'"
- (let (front)
- (while (and list (not (funcall pred (car list))))
- (push (car list) front)
- (!cdr list))
- (if list
- (-concat (nreverse front) (cdr list))
- (nreverse front))))
-
-(defmacro --remove-first (form list)
- "Anaphoric form of `-remove-first'."
- (declare (debug (form form)))
- `(-remove-first (lambda (it) ,form) ,list))
-
-(defalias '-reject-first '-remove-first)
-(defalias '--reject-first '--remove-first)
-
-(defun -remove-last (pred list)
- "Return a new list with the last item matching PRED removed.
-
-Alias: `-reject-last'
-
-See also: `-remove', `-map-last'"
- (nreverse (-remove-first pred (reverse list))))
-
-(defmacro --remove-last (form list)
- "Anaphoric form of `-remove-last'."
- (declare (debug (form form)))
- `(-remove-last (lambda (it) ,form) ,list))
-
-(defalias '-reject-last '-remove-last)
-(defalias '--reject-last '--remove-last)
-
-(defun -remove-item (item list)
- "Remove all occurrences of ITEM from LIST.
-
-Comparison is done with `equal'."
- (declare (pure t) (side-effect-free t))
- (--remove (equal it item) list))
-
-(defmacro --keep (form list)
- "Anaphoric form of `-keep'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result"))
- (m (make-symbol "mapped")))
- `(let (,r)
- (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r))))
- (nreverse ,r))))
-
-(defun -keep (fn list)
- "Return a new list of the non-nil results of applying FN to the items in LIST.
-
-If you want to select the original items satisfying a predicate use `-filter'."
- (--keep (funcall fn it) list))
-
-(defun -non-nil (list)
- "Return all non-nil elements of LIST."
- (declare (pure t) (side-effect-free t))
- (-remove 'null list))
-
-(defmacro --map-indexed (form list)
- "Anaphoric form of `-map-indexed'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each ,list
- (!cons ,form ,r))
- (nreverse ,r))))
-
-(defun -map-indexed (fn list)
- "Return a new list consisting of the result of (FN index item) for each item in LIST.
-
-In the anaphoric form `--map-indexed', the index is exposed as symbol `it-index'.
-
-See also: `-each-indexed'."
- (--map-indexed (funcall fn it-index it) list))
-
-(defmacro --map-when (pred rep list)
- "Anaphoric form of `-map-when'."
- (declare (debug (form form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each ,list (!cons (if ,pred ,rep it) ,r))
- (nreverse ,r))))
-
-(defun -map-when (pred rep list)
- "Return a new list where the elements in LIST that do not match the PRED function
-are unchanged, and where the elements in LIST that do match the PRED function are mapped
-through the REP function.
-
-Alias: `-replace-where'
-
-See also: `-update-at'"
- (--map-when (funcall pred it) (funcall rep it) list))
-
-(defalias '-replace-where '-map-when)
-(defalias '--replace-where '--map-when)
-
-(defun -map-first (pred rep list)
- "Replace first item in LIST satisfying PRED with result of REP called on this item.
-
-See also: `-map-when', `-replace-first'"
- (let (front)
- (while (and list (not (funcall pred (car list))))
- (push (car list) front)
- (!cdr list))
- (if list
- (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list)))
- (nreverse front))))
-
-(defmacro --map-first (pred rep list)
- "Anaphoric form of `-map-first'."
- `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
-
-(defun -map-last (pred rep list)
- "Replace last item in LIST satisfying PRED with result of REP called on this item.
-
-See also: `-map-when', `-replace-last'"
- (nreverse (-map-first pred rep (reverse list))))
-
-(defmacro --map-last (pred rep list)
- "Anaphoric form of `-map-last'."
- `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
-
-(defun -replace (old new list)
- "Replace all OLD items in LIST with NEW.
-
-Elements are compared using `equal'.
-
-See also: `-replace-at'"
- (declare (pure t) (side-effect-free t))
- (--map-when (equal it old) new list))
-
-(defun -replace-first (old new list)
- "Replace the first occurrence of OLD with NEW in LIST.
-
-Elements are compared using `equal'.
-
-See also: `-map-first'"
- (declare (pure t) (side-effect-free t))
- (--map-first (equal old it) new list))
-
-(defun -replace-last (old new list)
- "Replace the last occurrence of OLD with NEW in LIST.
-
-Elements are compared using `equal'.
-
-See also: `-map-last'"
- (declare (pure t) (side-effect-free t))
- (--map-last (equal old it) new list))
-
-(defmacro --mapcat (form list)
- "Anaphoric form of `-mapcat'."
- (declare (debug (form form)))
- `(apply 'append (--map ,form ,list)))
-
-(defun -mapcat (fn list)
- "Return the concatenation of the result of mapping FN over LIST.
-Thus function FN should return a list."
- (--mapcat (funcall fn it) list))
-
-(defun -flatten (l)
- "Take a nested list L and return its contents as a single, flat list.
-
-Note that because `nil' represents a list of zero elements (an
-empty list), any mention of nil in L will disappear after
-flattening. If you need to preserve nils, consider `-flatten-n'
-or map them to some unique symbol and then map them back.
-
-Conses of two atoms are considered \"terminals\", that is, they
-aren't flattened further.
-
-See also: `-flatten-n'"
- (declare (pure t) (side-effect-free t))
- (if (and (listp l) (listp (cdr l)))
- (-mapcat '-flatten l)
- (list l)))
-
-(defmacro --iterate (form init n)
- "Anaphoric version of `-iterate'."
- (declare (debug (form form form)))
- `(-iterate (lambda (it) ,form) ,init ,n))
-
-(defun -flatten-n (num list)
- "Flatten NUM levels of a nested LIST.
-
-See also: `-flatten'"
- (declare (pure t) (side-effect-free t))
- (-last-item (--iterate (--mapcat (-list it) it) list (1+ num))))
-
-(defun -concat (&rest lists)
- "Return a new list with the concatenation of the elements in the supplied LISTS."
- (declare (pure t) (side-effect-free t))
- (apply 'append lists))
-
-(defalias '-copy 'copy-sequence
- "Create a shallow copy of LIST.
-
-\(fn LIST)")
-
-(defun -splice (pred fun list)
- "Splice lists generated by FUN in place of elements matching PRED in LIST.
-
-FUN takes the element matching PRED as input.
-
-This function can be used as replacement for `,@' in case you
-need to splice several lists at marked positions (for example
-with keywords).
-
-See also: `-splice-list', `-insert-at'"
- (let (r)
- (--each list
- (if (funcall pred it)
- (let ((new (funcall fun it)))
- (--each new (!cons it r)))
- (!cons it r)))
- (nreverse r)))
-
-(defmacro --splice (pred form list)
- "Anaphoric form of `-splice'."
- `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list))
-
-(defun -splice-list (pred new-list list)
- "Splice NEW-LIST in place of elements matching PRED in LIST.
-
-See also: `-splice', `-insert-at'"
- (-splice pred (lambda (_) new-list) list))
-
-(defmacro --splice-list (pred new-list list)
- "Anaphoric form of `-splice-list'."
- `(-splice-list (lambda (it) ,pred) ,new-list ,list))
-
-(defun -cons* (&rest args)
- "Make a new list from the elements of ARGS.
-
-The last 2 members of ARGS are used as the final cons of the
-result so if the final member of ARGS is not a list the result is
-a dotted list."
- (declare (pure t) (side-effect-free t))
- (-reduce-r 'cons args))
-
-(defun -snoc (list elem &rest elements)
- "Append ELEM to the end of the list.
-
-This is like `cons', but operates on the end of list.
-
-If ELEMENTS is non nil, append these to the list as well."
- (-concat list (list elem) elements))
-
-(defmacro --first (form list)
- "Anaphoric form of `-first'."
- (declare (debug (form form)))
- (let ((n (make-symbol "needle")))
- `(let (,n)
- (--each-while ,list (not ,n)
- (when ,form (setq ,n it)))
- ,n)))
-
-(defun -first (pred list)
- "Return the first x in LIST where (PRED x) is non-nil, else nil.
-
-To get the first item in the list no questions asked, use `car'.
-
-Alias: `-find'"
- (--first (funcall pred it) list))
-
-(defalias '-find '-first)
-(defalias '--find '--first)
-
-(defmacro --some (form list)
- "Anaphoric form of `-some'."
- (declare (debug (form form)))
- (let ((n (make-symbol "needle")))
- `(let (,n)
- (--each-while ,list (not ,n)
- (setq ,n ,form))
- ,n)))
-
-(defun -some (pred list)
- "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil.
-
-Alias: `-any'"
- (--some (funcall pred it) list))
-
-(defalias '-any '-some)
-(defalias '--any '--some)
-
-(defmacro --last (form list)
- "Anaphoric form of `-last'."
- (declare (debug (form form)))
- (let ((n (make-symbol "needle")))
- `(let (,n)
- (--each ,list
- (when ,form (setq ,n it)))
- ,n)))
-
-(defun -last (pred list)
- "Return the last x in LIST where (PRED x) is non-nil, else nil."
- (--last (funcall pred it) list))
-
-(defalias '-first-item 'car
- "Return the first item of LIST, or nil on an empty list.
-
-See also: `-second-item', `-last-item'.
-
-\(fn LIST)")
-
-;; Ensure that calls to `-first-item' are compiled to a single opcode,
-;; just like `car'.
-(put '-first-item 'byte-opcode 'byte-car)
-(put '-first-item 'byte-compile 'byte-compile-one-arg)
-
-(defalias '-second-item 'cadr
- "Return the second item of LIST, or nil if LIST is too short.
-
-See also: `-third-item'.
-
-\(fn LIST)")
-
-(defalias '-third-item
- (if (fboundp 'caddr)
- #'caddr
- (lambda (list) (car (cddr list))))
- "Return the third item of LIST, or nil if LIST is too short.
-
-See also: `-fourth-item'.
-
-\(fn LIST)")
-
-(defun -fourth-item (list)
- "Return the fourth item of LIST, or nil if LIST is too short.
-
-See also: `-fifth-item'."
- (declare (pure t) (side-effect-free t))
- (car (cdr (cdr (cdr list)))))
-
-(defun -fifth-item (list)
- "Return the fifth item of LIST, or nil if LIST is too short.
-
-See also: `-last-item'."
- (declare (pure t) (side-effect-free t))
- (car (cdr (cdr (cdr (cdr list))))))
-
-(defun -last-item (list)
- "Return the last item of LIST, or nil on an empty list."
- (declare (pure t) (side-effect-free t))
- (car (last list)))
-
-;; Use `with-no-warnings' to suppress unbound `-last-item' or
-;; undefined `gv--defsetter' warnings arising from both
-;; `gv-define-setter' and `defsetf' in certain Emacs versions.
-(with-no-warnings
- (if (fboundp 'gv-define-setter)
- (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val))
- (defsetf -last-item (x) (val) `(setcar (last ,x) ,val))))
-
-(defun -butlast (list)
- "Return a list of all items in list except for the last."
- ;; no alias as we don't want magic optional argument
- (declare (pure t) (side-effect-free t))
- (butlast list))
-
-(defmacro --count (pred list)
- "Anaphoric form of `-count'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let ((,r 0))
- (--each ,list (when ,pred (setq ,r (1+ ,r))))
- ,r)))
-
-(defun -count (pred list)
- "Counts the number of items in LIST where (PRED item) is non-nil."
- (--count (funcall pred it) list))
-
-(defun ---truthy? (val)
- (declare (pure t) (side-effect-free t))
- (not (null val)))
-
-(defmacro --any? (form list)
- "Anaphoric form of `-any?'."
- (declare (debug (form form)))
- `(---truthy? (--some ,form ,list)))
-
-(defun -any? (pred list)
- "Return t if (PRED x) is non-nil for any x in LIST, else nil.
-
-Alias: `-any-p', `-some?', `-some-p'"
- (--any? (funcall pred it) list))
-
-(defalias '-some? '-any?)
-(defalias '--some? '--any?)
-(defalias '-any-p '-any?)
-(defalias '--any-p '--any?)
-(defalias '-some-p '-any?)
-(defalias '--some-p '--any?)
-
-(defmacro --all? (form list)
- "Anaphoric form of `-all?'."
- (declare (debug (form form)))
- (let ((a (make-symbol "all")))
- `(let ((,a t))
- (--each-while ,list ,a (setq ,a ,form))
- (---truthy? ,a))))
-
-(defun -all? (pred list)
- "Return t if (PRED x) is non-nil for all x in LIST, else nil.
-
-Alias: `-all-p', `-every?', `-every-p'"
- (--all? (funcall pred it) list))
-
-(defalias '-every? '-all?)
-(defalias '--every? '--all?)
-(defalias '-all-p '-all?)
-(defalias '--all-p '--all?)
-(defalias '-every-p '-all?)
-(defalias '--every-p '--all?)
-
-(defmacro --none? (form list)
- "Anaphoric form of `-none?'."
- (declare (debug (form form)))
- `(--all? (not ,form) ,list))
-
-(defun -none? (pred list)
- "Return t if (PRED x) is nil for all x in LIST, else nil.
-
-Alias: `-none-p'"
- (--none? (funcall pred it) list))
-
-(defalias '-none-p '-none?)
-(defalias '--none-p '--none?)
-
-(defmacro --only-some? (form list)
- "Anaphoric form of `-only-some?'."
- (declare (debug (form form)))
- (let ((y (make-symbol "yes"))
- (n (make-symbol "no")))
- `(let (,y ,n)
- (--each-while ,list (not (and ,y ,n))
- (if ,form (setq ,y t) (setq ,n t)))
- (---truthy? (and ,y ,n)))))
-
-(defun -only-some? (pred list)
- "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED.
-Return `nil` both if all items match the predicate or if none of the items match the predicate.
-
-Alias: `-only-some-p'"
- (--only-some? (funcall pred it) list))
-
-(defalias '-only-some-p '-only-some?)
-(defalias '--only-some-p '--only-some?)
-
-(defun -slice (list from &optional to step)
- "Return copy of LIST, starting from index FROM to index TO.
-
-FROM or TO may be negative. These values are then interpreted
-modulo the length of the list.
-
-If STEP is a number, only each STEPth item in the resulting
-section is returned. Defaults to 1."
- (declare (pure t) (side-effect-free t))
- (let ((length (length list))
- (new-list nil))
- ;; to defaults to the end of the list
- (setq to (or to length))
- (setq step (or step 1))
- ;; handle negative indices
- (when (< from 0)
- (setq from (mod from length)))
- (when (< to 0)
- (setq to (mod to length)))
-
- ;; iterate through the list, keeping the elements we want
- (--each-while list (< it-index to)
- (when (and (>= it-index from)
- (= (mod (- from it-index) step) 0))
- (push it new-list)))
- (nreverse new-list)))
-
-(defun -take (n list)
- "Return a new list of the first N items in LIST, or all items if there are fewer than N.
-
-See also: `-take-last'"
- (declare (pure t) (side-effect-free t))
- (let (result)
- (--dotimes n
- (when list
- (!cons (car list) result)
- (!cdr list)))
- (nreverse result)))
-
-(defun -take-last (n list)
- "Return the last N items of LIST in order.
-
-See also: `-take'"
- (declare (pure t) (side-effect-free t))
- (copy-sequence (last list n)))
-
-(defalias '-drop 'nthcdr
- "Return the tail of LIST without the first N items.
-
-See also: `-drop-last'
-
-\(fn N LIST)")
-
-(defun -drop-last (n list)
- "Remove the last N items of LIST and return a copy.
-
-See also: `-drop'"
- ;; No alias because we don't want magic optional argument
- (declare (pure t) (side-effect-free t))
- (butlast list n))
-
-(defmacro --take-while (form list)
- "Anaphoric form of `-take-while'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each-while ,list ,form (!cons it ,r))
- (nreverse ,r))))
-
-(defun -take-while (pred list)
- "Return a new list of successive items from LIST while (PRED item) returns a non-nil value."
- (--take-while (funcall pred it) list))
-
-(defmacro --drop-while (form list)
- "Anaphoric form of `-drop-while'."
- (declare (debug (form form)))
- (let ((l (make-symbol "list")))
- `(let ((,l ,list))
- (while (and ,l (let ((it (car ,l))) ,form))
- (!cdr ,l))
- ,l)))
-
-(defun -drop-while (pred list)
- "Return the tail of LIST starting from the first item for which (PRED item) returns nil."
- (--drop-while (funcall pred it) list))
-
-(defun -split-at (n list)
- "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list."
- (declare (pure t) (side-effect-free t))
- (let (result)
- (--dotimes n
- (when list
- (!cons (car list) result)
- (!cdr list)))
- (list (nreverse result) list)))
-
-(defun -rotate (n list)
- "Rotate LIST N places to the right. With N negative, rotate to the left.
-The time complexity is O(n)."
- (declare (pure t) (side-effect-free t))
- (when list
- (let* ((len (length list))
- (n-mod-len (mod n len))
- (new-tail-len (- len n-mod-len)))
- (append (-drop new-tail-len list) (-take new-tail-len list)))))
-
-(defun -insert-at (n x list)
- "Return a list with X inserted into LIST at position N.
-
-See also: `-splice', `-splice-list'"
- (declare (pure t) (side-effect-free t))
- (let ((split-list (-split-at n list)))
- (nconc (car split-list) (cons x (cadr split-list)))))
-
-(defun -replace-at (n x list)
- "Return a list with element at Nth position in LIST replaced with X.
-
-See also: `-replace'"
- (declare (pure t) (side-effect-free t))
- (let ((split-list (-split-at n list)))
- (nconc (car split-list) (cons x (cdr (cadr split-list))))))
-
-(defun -update-at (n func list)
- "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.
-
-See also: `-map-when'"
- (let ((split-list (-split-at n list)))
- (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list))))))
-
-(defmacro --update-at (n form list)
- "Anaphoric version of `-update-at'."
- (declare (debug (form form form)))
- `(-update-at ,n (lambda (it) ,form) ,list))
-
-(defun -remove-at (n list)
- "Return a list with element at Nth position in LIST removed.
-
-See also: `-remove-at-indices', `-remove'"
- (declare (pure t) (side-effect-free t))
- (-remove-at-indices (list n) list))
-
-(defun -remove-at-indices (indices list)
- "Return a list whose elements are elements from LIST without
-elements selected as `(nth i list)` for all i
-from INDICES.
-
-See also: `-remove-at', `-remove'"
- (declare (pure t) (side-effect-free t))
- (let* ((indices (-sort '< indices))
- (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices))))
- r)
- (--each diffs
- (let ((split (-split-at it list)))
- (!cons (car split) r)
- (setq list (cdr (cadr split)))))
- (!cons list r)
- (apply '-concat (nreverse r))))
-
-(defmacro --split-with (pred list)
- "Anaphoric form of `-split-with'."
- (declare (debug (form form)))
- (let ((l (make-symbol "list"))
- (r (make-symbol "result"))
- (c (make-symbol "continue")))
- `(let ((,l ,list)
- (,r nil)
- (,c t))
- (while (and ,l ,c)
- (let ((it (car ,l)))
- (if (not ,pred)
- (setq ,c nil)
- (!cons it ,r)
- (!cdr ,l))))
- (list (nreverse ,r) ,l))))
-
-(defun -split-with (pred list)
- "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list."
- (--split-with (funcall pred it) list))
-
-(defmacro -split-on (item list)
- "Split the LIST each time ITEM is found.
-
-Unlike `-partition-by', the ITEM is discarded from the results.
-Empty lists are also removed from the result.
-
-Comparison is done by `equal'.
-
-See also `-split-when'"
- (declare (debug (form form)))
- `(-split-when (lambda (it) (equal it ,item)) ,list))
-
-(defmacro --split-when (form list)
- "Anaphoric version of `-split-when'."
- (declare (debug (form form)))
- `(-split-when (lambda (it) ,form) ,list))
-
-(defun -split-when (fn list)
- "Split the LIST on each element where FN returns non-nil.
-
-Unlike `-partition-by', the \"matched\" element is discarded from
-the results. Empty lists are also removed from the result.
-
-This function can be thought of as a generalization of
-`split-string'."
- (let (r s)
- (while list
- (if (not (funcall fn (car list)))
- (push (car list) s)
- (when s (push (nreverse s) r))
- (setq s nil))
- (!cdr list))
- (when s (push (nreverse s) r))
- (nreverse r)))
-
-(defmacro --separate (form list)
- "Anaphoric form of `-separate'."
- (declare (debug (form form)))
- (let ((y (make-symbol "yes"))
- (n (make-symbol "no")))
- `(let (,y ,n)
- (--each ,list (if ,form (!cons it ,y) (!cons it ,n)))
- (list (nreverse ,y) (nreverse ,n)))))
-
-(defun -separate (pred list)
- "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list."
- (--separate (funcall pred it) list))
-
-(defun ---partition-all-in-steps-reversed (n step list)
- "Private: Used by -partition-all-in-steps and -partition-in-steps."
- (when (< step 1)
- (error "Step must be a positive number, or you're looking at some juicy infinite loops."))
- (let ((result nil))
- (while list
- (!cons (-take n list) result)
- (setq list (-drop step list)))
- result))
-
-(defun -partition-all-in-steps (n step list)
- "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
-The last groups may contain less than N items."
- (declare (pure t) (side-effect-free t))
- (nreverse (---partition-all-in-steps-reversed n step list)))
-
-(defun -partition-in-steps (n step list)
- "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
-If there are not enough items to make the last group N-sized,
-those items are discarded."
- (declare (pure t) (side-effect-free t))
- (let ((result (---partition-all-in-steps-reversed n step list)))
- (while (and result (< (length (car result)) n))
- (!cdr result))
- (nreverse result)))
-
-(defun -partition-all (n list)
- "Return a new list with the items in LIST grouped into N-sized sublists.
-The last group may contain less than N items."
- (declare (pure t) (side-effect-free t))
- (-partition-all-in-steps n n list))
-
-(defun -partition (n list)
- "Return a new list with the items in LIST grouped into N-sized sublists.
-If there are not enough items to make the last group N-sized,
-those items are discarded."
- (declare (pure t) (side-effect-free t))
- (-partition-in-steps n n list))
-
-(defmacro --partition-by (form list)
- "Anaphoric form of `-partition-by'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result"))
- (s (make-symbol "sublist"))
- (v (make-symbol "value"))
- (n (make-symbol "new-value"))
- (l (make-symbol "list")))
- `(let ((,l ,list))
- (when ,l
- (let* ((,r nil)
- (it (car ,l))
- (,s (list it))
- (,v ,form)
- (,l (cdr ,l)))
- (while ,l
- (let* ((it (car ,l))
- (,n ,form))
- (unless (equal ,v ,n)
- (!cons (nreverse ,s) ,r)
- (setq ,s nil)
- (setq ,v ,n))
- (!cons it ,s)
- (!cdr ,l)))
- (!cons (nreverse ,s) ,r)
- (nreverse ,r))))))
-
-(defun -partition-by (fn list)
- "Apply FN to each item in LIST, splitting it each time FN returns a new value."
- (--partition-by (funcall fn it) list))
-
-(defmacro --partition-by-header (form list)
- "Anaphoric form of `-partition-by-header'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result"))
- (s (make-symbol "sublist"))
- (h (make-symbol "header-value"))
- (b (make-symbol "seen-body?"))
- (n (make-symbol "new-value"))
- (l (make-symbol "list")))
- `(let ((,l ,list))
- (when ,l
- (let* ((,r nil)
- (it (car ,l))
- (,s (list it))
- (,h ,form)
- (,b nil)
- (,l (cdr ,l)))
- (while ,l
- (let* ((it (car ,l))
- (,n ,form))
- (if (equal ,h ,n)
- (when ,b
- (!cons (nreverse ,s) ,r)
- (setq ,s nil)
- (setq ,b nil))
- (setq ,b t))
- (!cons it ,s)
- (!cdr ,l)))
- (!cons (nreverse ,s) ,r)
- (nreverse ,r))))))
-
-(defun -partition-by-header (fn list)
- "Apply FN to the first item in LIST. That is the header
-value. Apply FN to each item in LIST, splitting it each time FN
-returns the header value, but only after seeing at least one
-other value (the body)."
- (--partition-by-header (funcall fn it) list))
-
-(defun -partition-after-pred (pred list)
- "Partition directly after each time PRED is true on an element of LIST."
- (when list
- (let ((rest (-partition-after-pred pred
- (cdr list))))
- (if (funcall pred (car list))
- ;;split after (car list)
- (cons (list (car list))
- rest)
-
- ;;don't split after (car list)
- (cons (cons (car list)
- (car rest))
- (cdr rest))))))
-
-(defun -partition-before-pred (pred list)
- "Partition directly before each time PRED is true on an element of LIST."
- (nreverse (-map #'reverse
- (-partition-after-pred pred (reverse list)))))
-
-(defun -partition-after-item (item list)
- "Partition directly after each time ITEM appears in LIST."
- (-partition-after-pred (lambda (ele) (equal ele item))
- list))
-
-(defun -partition-before-item (item list)
- "Partition directly before each time ITEM appears in LIST."
- (-partition-before-pred (lambda (ele) (equal ele item))
- list))
-
-(defmacro --group-by (form list)
- "Anaphoric form of `-group-by'."
- (declare (debug t))
- (let ((n (make-symbol "n"))
- (k (make-symbol "k"))
- (grp (make-symbol "grp")))
- `(nreverse
- (-map
- (lambda (,n)
- (cons (car ,n)
- (nreverse (cdr ,n))))
- (--reduce-from
- (let* ((,k (,@form))
- (,grp (assoc ,k acc)))
- (if ,grp
- (setcdr ,grp (cons it (cdr ,grp)))
- (push
- (list ,k it)
- acc))
- acc)
- nil ,list)))))
-
-(defun -group-by (fn list)
- "Separate LIST into an alist whose keys are FN applied to the
-elements of LIST. Keys are compared by `equal'."
- (--group-by (funcall fn it) list))
-
-(defun -interpose (sep list)
- "Return a new list of all elements in LIST separated by SEP."
- (declare (pure t) (side-effect-free t))
- (let (result)
- (when list
- (!cons (car list) result)
- (!cdr list))
- (while list
- (setq result (cons (car list) (cons sep result)))
- (!cdr list))
- (nreverse result)))
-
-(defun -interleave (&rest lists)
- "Return a new list of the first item in each list, then the second etc."
- (declare (pure t) (side-effect-free t))
- (when lists
- (let (result)
- (while (-none? 'null lists)
- (--each lists (!cons (car it) result))
- (setq lists (-map 'cdr lists)))
- (nreverse result))))
-
-(defmacro --zip-with (form list1 list2)
- "Anaphoric form of `-zip-with'.
-
-The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'."
- (declare (debug (form form form)))
- (let ((r (make-symbol "result"))
- (l1 (make-symbol "list1"))
- (l2 (make-symbol "list2")))
- `(let ((,r nil)
- (,l1 ,list1)
- (,l2 ,list2))
- (while (and ,l1 ,l2)
- (let ((it (car ,l1))
- (other (car ,l2)))
- (!cons ,form ,r)
- (!cdr ,l1)
- (!cdr ,l2)))
- (nreverse ,r))))
-
-(defun -zip-with (fn list1 list2)
- "Zip the two lists LIST1 and LIST2 using a function FN. This
-function is applied pairwise taking as first argument element of
-LIST1 and as second argument element of LIST2 at corresponding
-position.
-
-The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it',
-and the elements from LIST2 as symbol `other'."
- (--zip-with (funcall fn it other) list1 list2))
-
-(defun -zip-lists (&rest lists)
- "Zip LISTS together. Group the head of each list, followed by the
-second elements of each list, and so on. The lengths of the returned
-groupings are equal to the length of the shortest input list.
-
-The return value is always list of lists, which is a difference
-from `-zip-pair' which returns a cons-cell in case two input
-lists are provided.
-
-See also: `-zip'"
- (declare (pure t) (side-effect-free t))
- (when lists
- (let (results)
- (while (-none? 'null lists)
- (setq results (cons (mapcar 'car lists) results))
- (setq lists (mapcar 'cdr lists)))
- (nreverse results))))
-
-(defun -zip (&rest lists)
- "Zip LISTS together. Group the head of each list, followed by the
-second elements of each list, and so on. The lengths of the returned
-groupings are equal to the length of the shortest input list.
-
-If two lists are provided as arguments, return the groupings as a list
-of cons cells. Otherwise, return the groupings as a list of lists.
-
-Use `-zip-lists' if you need the return value to always be a list
-of lists.
-
-Alias: `-zip-pair'
-
-See also: `-zip-lists'"
- (declare (pure t) (side-effect-free t))
- (when lists
- (let (results)
- (while (-none? 'null lists)
- (setq results (cons (mapcar 'car lists) results))
- (setq lists (mapcar 'cdr lists)))
- (setq results (nreverse results))
- (if (= (length lists) 2)
- ;; to support backward compatibility, return
- ;; a cons cell if two lists were provided
- (--map (cons (car it) (cadr it)) results)
- results))))
-
-(defalias '-zip-pair '-zip)
-
-(defun -zip-fill (fill-value &rest lists)
- "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
-lengths of the returned groupings are equal to the length of the
-longest input list."
- (declare (pure t) (side-effect-free t))
- (apply '-zip (apply '-pad (cons fill-value lists))))
-
-(defun -unzip (lists)
- "Unzip LISTS.
-
-This works just like `-zip' but takes a list of lists instead of
-a variable number of arguments, such that
-
- (-unzip (-zip L1 L2 L3 ...))
-
-is identity (given that the lists are the same length).
-
-Note in particular that calling this on a list of two lists will
-return a list of cons-cells such that the aboce identity works.
-
-See also: `-zip'"
- (apply '-zip lists))
-
-(defun -cycle (list)
- "Return an infinite copy of LIST that will cycle through the
-elements and repeat from the beginning."
- (declare (pure t) (side-effect-free t))
- (let ((newlist (-map 'identity list)))
- (nconc newlist newlist)))
-
-(defun -pad (fill-value &rest lists)
- "Appends FILL-VALUE to the end of each list in LISTS such that they
-will all have the same length."
- (let* ((annotations (-annotate 'length lists))
- (n (-max (-map 'car annotations))))
- (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations)))
-
-(defun -annotate (fn list)
- "Return a list of cons cells where each cell is FN applied to each
-element of LIST paired with the unmodified element of LIST."
- (-zip (-map fn list) list))
-
-(defmacro --annotate (form list)
- "Anaphoric version of `-annotate'."
- (declare (debug (form form)))
- `(-annotate (lambda (it) ,form) ,list))
-
-(defun dash--table-carry (lists restore-lists &optional re)
- "Helper for `-table' and `-table-flat'.
-
-If a list overflows, carry to the right and reset the list."
- (while (not (or (car lists)
- (equal lists '(nil))))
- (setcar lists (car restore-lists))
- (pop (cadr lists))
- (!cdr lists)
- (!cdr restore-lists)
- (when re
- (push (nreverse (car re)) (cadr re))
- (setcar re nil)
- (!cdr re))))
-
-(defun -table (fn &rest lists)
- "Compute outer product of LISTS using function FN.
-
-The function FN should have the same arity as the number of
-supplied lists.
-
-The outer product is computed by applying fn to all possible
-combinations created by taking one element from each list in
-order. The dimension of the result is (length lists).
-
-See also: `-table-flat'"
- (let ((restore-lists (copy-sequence lists))
- (last-list (last lists))
- (re (make-list (length lists) nil)))
- (while (car last-list)
- (let ((item (apply fn (-map 'car lists))))
- (push item (car re))
- (setcar lists (cdar lists)) ;; silence byte compiler
- (dash--table-carry lists restore-lists re)))
- (nreverse (car (last re)))))
-
-(defun -table-flat (fn &rest lists)
- "Compute flat outer product of LISTS using function FN.
-
-The function FN should have the same arity as the number of
-supplied lists.
-
-The outer product is computed by applying fn to all possible
-combinations created by taking one element from each list in
-order. The results are flattened, ignoring the tensor structure
-of the result. This is equivalent to calling:
-
- (-flatten-n (1- (length lists)) (apply \\='-table fn lists))
-
-but the implementation here is much more efficient.
-
-See also: `-flatten-n', `-table'"
- (let ((restore-lists (copy-sequence lists))
- (last-list (last lists))
- re)
- (while (car last-list)
- (let ((item (apply fn (-map 'car lists))))
- (push item re)
- (setcar lists (cdar lists)) ;; silence byte compiler
- (dash--table-carry lists restore-lists)))
- (nreverse re)))
-
-(defun -partial (fn &rest args)
- "Take a function FN and fewer than the normal arguments to FN,
-and return a fn that takes a variable number of additional ARGS.
-When called, the returned function calls FN with ARGS first and
-then additional args."
- (apply 'apply-partially fn args))
-
-(defun -elem-index (elem list)
- "Return the index of the first element in the given LIST which
-is equal to the query element ELEM, or nil if there is no
-such element."
- (declare (pure t) (side-effect-free t))
- (car (-elem-indices elem list)))
-
-(defun -elem-indices (elem list)
- "Return the indices of all elements in LIST equal to the query
-element ELEM, in ascending order."
- (declare (pure t) (side-effect-free t))
- (-find-indices (-partial 'equal elem) list))
-
-(defun -find-indices (pred list)
- "Return the indices of all elements in LIST satisfying the
-predicate PRED, in ascending order."
- (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list)))
-
-(defmacro --find-indices (form list)
- "Anaphoric version of `-find-indices'."
- (declare (debug (form form)))
- `(-find-indices (lambda (it) ,form) ,list))
-
-(defun -find-index (pred list)
- "Take a predicate PRED and a LIST and return the index of the
-first element in the list satisfying the predicate, or nil if
-there is no such element.
-
-See also `-first'."
- (car (-find-indices pred list)))
-
-(defmacro --find-index (form list)
- "Anaphoric version of `-find-index'."
- (declare (debug (form form)))
- `(-find-index (lambda (it) ,form) ,list))
-
-(defun -find-last-index (pred list)
- "Take a predicate PRED and a LIST and return the index of the
-last element in the list satisfying the predicate, or nil if
-there is no such element.
-
-See also `-last'."
- (-last-item (-find-indices pred list)))
-
-(defmacro --find-last-index (form list)
- "Anaphoric version of `-find-last-index'."
- `(-find-last-index (lambda (it) ,form) ,list))
-
-(defun -select-by-indices (indices list)
- "Return a list whose elements are elements from LIST selected
-as `(nth i list)` for all i from INDICES."
- (declare (pure t) (side-effect-free t))
- (let (r)
- (--each indices
- (!cons (nth it list) r))
- (nreverse r)))
-
-(defun -select-columns (columns table)
- "Select COLUMNS from TABLE.
-
-TABLE is a list of lists where each element represents one row.
-It is assumed each row has the same length.
-
-Each row is transformed such that only the specified COLUMNS are
-selected.
-
-See also: `-select-column', `-select-by-indices'"
- (declare (pure t) (side-effect-free t))
- (--map (-select-by-indices columns it) table))
-
-(defun -select-column (column table)
- "Select COLUMN from TABLE.
-
-TABLE is a list of lists where each element represents one row.
-It is assumed each row has the same length.
-
-The single selected column is returned as a list.
-
-See also: `-select-columns', `-select-by-indices'"
- (declare (pure t) (side-effect-free t))
- (--mapcat (-select-by-indices (list column) it) table))
-
-(defmacro -> (x &optional form &rest more)
- "Thread the expr through the forms. Insert X as the second item
-in the first form, making a list of it if it is not a list
-already. If there are more forms, insert the first form as the
-second item in second form, etc."
- (declare (debug (form &rest [&or symbolp (sexp &rest form)])))
- (cond
- ((null form) x)
- ((null more) (if (listp form)
- `(,(car form) ,x ,@(cdr form))
- (list form x)))
- (:else `(-> (-> ,x ,form) ,@more))))
-
-(defmacro ->> (x &optional form &rest more)
- "Thread the expr through the forms. Insert X as the last item
-in the first form, making a list of it if it is not a list
-already. If there are more forms, insert the first form as the
-last item in second form, etc."
- (declare (debug ->))
- (cond
- ((null form) x)
- ((null more) (if (listp form)
- `(,@form ,x)
- (list form x)))
- (:else `(->> (->> ,x ,form) ,@more))))
-
-(defmacro --> (x &rest forms)
- "Starting with the value of X, thread each expression through FORMS.
-
-Insert X at the position signified by the symbol `it' in the first
-form. If there are more forms, insert the first form at the position
-signified by `it' in in second form, etc."
- (declare (debug (form body)))
- `(-as-> ,x it ,@forms))
-
-(defmacro -as-> (value variable &rest forms)
- "Starting with VALUE, thread VARIABLE through FORMS.
-
-In the first form, bind VARIABLE to VALUE. In the second form, bind
-VARIABLE to the result of the first form, and so forth."
- (declare (debug (form symbolp body)))
- (if (null forms)
- `,value
- `(let ((,variable ,value))
- (-as-> ,(if (symbolp (car forms))
- (list (car forms) variable)
- (car forms))
- ,variable
- ,@(cdr forms)))))
-
-(defmacro -some-> (x &optional form &rest more)
- "When expr is non-nil, thread it through the first form (via `->'),
-and when that result is non-nil, through the next form, etc."
- (declare (debug ->)
- (indent 1))
- (if (null form) x
- (let ((result (make-symbol "result")))
- `(-some-> (-when-let (,result ,x)
- (-> ,result ,form))
- ,@more))))
-
-(defmacro -some->> (x &optional form &rest more)
- "When expr is non-nil, thread it through the first form (via `->>'),
-and when that result is non-nil, through the next form, etc."
- (declare (debug ->)
- (indent 1))
- (if (null form) x
- (let ((result (make-symbol "result")))
- `(-some->> (-when-let (,result ,x)
- (->> ,result ,form))
- ,@more))))
-
-(defmacro -some--> (x &optional form &rest more)
- "When expr in non-nil, thread it through the first form (via `-->'),
-and when that result is non-nil, through the next form, etc."
- (declare (debug ->)
- (indent 1))
- (if (null form) x
- (let ((result (make-symbol "result")))
- `(-some--> (-when-let (,result ,x)
- (--> ,result ,form))
- ,@more))))
-
-(defun -grade-up (comparator list)
- "Grade elements of LIST using COMPARATOR relation, yielding a
-permutation vector such that applying this permutation to LIST
-sorts it in ascending order."
- ;; ugly hack to "fix" lack of lexical scope
- (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other)))))
- (->> (--map-indexed (cons it it-index) list)
- (-sort comp)
- (-map 'cdr))))
-
-(defun -grade-down (comparator list)
- "Grade elements of LIST using COMPARATOR relation, yielding a
-permutation vector such that applying this permutation to LIST
-sorts it in descending order."
- ;; ugly hack to "fix" lack of lexical scope
- (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it)))))
- (->> (--map-indexed (cons it it-index) list)
- (-sort comp)
- (-map 'cdr))))
-
-(defvar dash--source-counter 0
- "Monotonic counter for generated symbols.")
-
-(defun dash--match-make-source-symbol ()
- "Generate a new dash-source symbol.
-
-All returned symbols are guaranteed to be unique."
- (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter))
- (setq dash--source-counter (1+ dash--source-counter))))
-
-(defun dash--match-ignore-place-p (symbol)
- "Return non-nil if SYMBOL is a symbol and starts with _."
- (and (symbolp symbol)
- (eq (aref (symbol-name symbol) 0) ?_)))
-
-(defun dash--match-cons-skip-cdr (skip-cdr source)
- "Helper function generating idiomatic shifting code."
- (cond
- ((= skip-cdr 0)
- `(pop ,source))
- (t
- `(prog1 ,(dash--match-cons-get-car skip-cdr source)
- (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source))))))
-
-(defun dash--match-cons-get-car (skip-cdr source)
- "Helper function generating idiomatic code to get nth car."
- (cond
- ((= skip-cdr 0)
- `(car ,source))
- ((= skip-cdr 1)
- `(cadr ,source))
- (t
- `(nth ,skip-cdr ,source))))
-
-(defun dash--match-cons-get-cdr (skip-cdr source)
- "Helper function generating idiomatic code to get nth cdr."
- (cond
- ((= skip-cdr 0)
- source)
- ((= skip-cdr 1)
- `(cdr ,source))
- (t
- `(nthcdr ,skip-cdr ,source))))
-
-(defun dash--match-cons (match-form source)
- "Setup a cons matching environment and call the real matcher."
- (let ((s (dash--match-make-source-symbol))
- (n 0)
- (m match-form))
- (while (and (consp m)
- (dash--match-ignore-place-p (car m)))
- (setq n (1+ n)) (!cdr m))
- (cond
- ;; when we only have one pattern in the list, we don't have to
- ;; create a temporary binding (--dash-source--) for the source
- ;; and just use the input directly
- ((and (consp m)
- (not (cdr m)))
- (dash--match (car m) (dash--match-cons-get-car n source)))
- ;; handle other special types
- ((> n 0)
- (dash--match m (dash--match-cons-get-cdr n source)))
- ;; this is the only entry-point for dash--match-cons-1, that's
- ;; why we can't simply use the above branch, it would produce
- ;; infinite recursion
- (t
- (cons (list s source) (dash--match-cons-1 match-form s))))))
-
-(defun dash--get-expand-function (type)
- "Get expand function name for TYPE."
- (intern-soft (format "dash-expand:%s" type)))
-
-(defun dash--match-cons-1 (match-form source &optional props)
- "Match MATCH-FORM against SOURCE.
-
-MATCH-FORM is a proper or improper list. Each element of
-MATCH-FORM is either a symbol, which gets bound to the respective
-value in source or another match form which gets destructured
-recursively.
-
-If the cdr of last cons cell in the list is `nil', matching stops
-there.
-
-SOURCE is a proper or improper list."
- (let ((skip-cdr (or (plist-get props :skip-cdr) 0)))
- (cond
- ((consp match-form)
- (cond
- ((cdr match-form)
- (cond
- ((and (symbolp (car match-form))
- (functionp (dash--get-expand-function (car match-form))))
- (dash--match-kv (dash--match-kv-normalize-match-form match-form) (dash--match-cons-get-cdr skip-cdr source)))
- ((dash--match-ignore-place-p (car match-form))
- (dash--match-cons-1 (cdr match-form) source
- (plist-put props :skip-cdr (1+ skip-cdr))))
- (t
- (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source))
- (dash--match-cons-1 (cdr match-form) source)))))
- (t ;; Last matching place, no need for shift
- (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source)))))
- ((eq match-form nil)
- nil)
- (t ;; Handle improper lists. Last matching place, no need for shift
- (dash--match match-form (dash--match-cons-get-cdr skip-cdr source))))))
-
-(defun dash--vector-tail (seq start)
- "Return the tail of SEQ starting at START."
- (cond
- ((vectorp seq)
- (let* ((re-length (- (length seq) start))
- (re (make-vector re-length 0)))
- (--dotimes re-length (aset re it (aref seq (+ it start))))
- re))
- ((stringp seq)
- (substring seq start))))
-
-(defun dash--match-vector (match-form source)
- "Setup a vector matching environment and call the real matcher."
- (let ((s (dash--match-make-source-symbol)))
- (cond
- ;; don't bind `s' if we only have one sub-pattern
- ((= (length match-form) 1)
- (dash--match (aref match-form 0) `(aref ,source 0)))
- ;; if the source is a symbol, we don't need to re-bind it
- ((symbolp source)
- (dash--match-vector-1 match-form source))
- ;; don't bind `s' if we only have one sub-pattern which is not ignored
- ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form))
- (ignored-places-n (length (-remove 'null ignored-places))))
- (when (= ignored-places-n (1- (length match-form)))
- (let ((n (-find-index 'null ignored-places)))
- (dash--match (aref match-form n) `(aref ,source ,n))))))
- (t
- (cons (list s source) (dash--match-vector-1 match-form s))))))
-
-(defun dash--match-vector-1 (match-form source)
- "Match MATCH-FORM against SOURCE.
-
-MATCH-FORM is a vector. Each element of MATCH-FORM is either a
-symbol, which gets bound to the respective value in source or
-another match form which gets destructured recursively.
-
-If second-from-last place in MATCH-FORM is the symbol &rest, the
-next element of the MATCH-FORM is matched against the tail of
-SOURCE, starting at index of the &rest symbol. This is
-conceptually the same as the (head . tail) match for improper
-lists, where dot plays the role of &rest.
-
-SOURCE is a vector.
-
-If the MATCH-FORM vector is shorter than SOURCE vector, only
-the (length MATCH-FORM) places are bound, the rest of the SOURCE
-is discarded."
- (let ((i 0)
- (l (length match-form))
- (re))
- (while (< i l)
- (let ((m (aref match-form i)))
- (push (cond
- ((and (symbolp m)
- (eq m '&rest))
- (prog1 (dash--match
- (aref match-form (1+ i))
- `(dash--vector-tail ,source ,i))
- (setq i l)))
- ((and (symbolp m)
- ;; do not match symbols starting with _
- (not (eq (aref (symbol-name m) 0) ?_)))
- (list (list m `(aref ,source ,i))))
- ((not (symbolp m))
- (dash--match m `(aref ,source ,i))))
- re)
- (setq i (1+ i))))
- (-flatten-n 1 (nreverse re))))
-
-(defun dash--match-kv-normalize-match-form (pattern)
- "Normalize kv PATTERN.
-
-This method normalizes PATTERN to the format expected by
-`dash--match-kv'. See `-let' for the specification."
- (let ((normalized (list (car pattern)))
- (skip nil)
- (fill-placeholder (make-symbol "--dash-fill-placeholder--")))
- (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern)))
- (lambda (pair)
- (let ((current (car pair))
- (next (cdr pair)))
- (if skip
- (setq skip nil)
- (if (or (eq fill-placeholder next)
- (not (or (and (symbolp next)
- (not (keywordp next))
- (not (eq next t))
- (not (eq next nil)))
- (and (consp next)
- (not (eq (car next) 'quote)))
- (vectorp next))))
- (progn
- (cond
- ((keywordp current)
- (push current normalized)
- (push (intern (substring (symbol-name current) 1)) normalized))
- ((stringp current)
- (push current normalized)
- (push (intern current) normalized))
- ((and (consp current)
- (eq (car current) 'quote))
- (push current normalized)
- (push (cadr current) normalized))
- (t (error "-let: found key `%s' in kv destructuring but its pattern `%s' is invalid and can not be derived from the key" current next)))
- (setq skip nil))
- (push current normalized)
- (push next normalized)
- (setq skip t))))))
- (nreverse normalized)))
-
-(defun dash--match-kv (match-form source)
- "Setup a kv matching environment and call the real matcher.
-
-kv can be any key-value store, such as plist, alist or hash-table."
- (let ((s (dash--match-make-source-symbol)))
- (cond
- ;; don't bind `s' if we only have one sub-pattern (&type key val)
- ((= (length match-form) 3)
- (dash--match-kv-1 (cdr match-form) source (car match-form)))
- ;; if the source is a symbol, we don't need to re-bind it
- ((symbolp source)
- (dash--match-kv-1 (cdr match-form) source (car match-form)))
- (t
- (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form)))))))
-
-(defun dash-expand:&hash (key source)
- "Generate extracting KEY from SOURCE for &hash destructuring."
- `(gethash ,key ,source))
-
-(defun dash-expand:&plist (key source)
- "Generate extracting KEY from SOURCE for &plist destructuring."
- `(plist-get ,source ,key))
-
-(defun dash-expand:&alist (key source)
- "Generate extracting KEY from SOURCE for &alist destructuring."
- `(cdr (assoc ,key ,source)))
-
-(defun dash-expand:&hash? (key source)
- "Generate extracting KEY from SOURCE for &hash? destructuring.
-Similar to &hash but check whether the map is not nil."
- (let ((src (make-symbol "src")))
- `(let ((,src ,source))
- (when ,src (gethash ,key ,src)))))
-
-(defalias 'dash-expand:&keys 'dash-expand:&plist)
-
-(defun dash--match-kv-1 (match-form source type)
- "Match MATCH-FORM against SOURCE of type TYPE.
-
-MATCH-FORM is a proper list of the form (key1 place1 ... keyN
-placeN). Each placeK is either a symbol, which gets bound to the
-value of keyK retrieved from the key-value store, or another
-match form which gets destructured recursively.
-
-SOURCE is a key-value store of type TYPE, which can be a plist,
-an alist or a hash table.
-
-TYPE is a token specifying the type of the key-value store.
-Valid values are &plist, &alist and &hash."
- (-flatten-n 1 (-map
- (lambda (kv)
- (let* ((k (car kv))
- (v (cadr kv))
- (getter
- (funcall (dash--get-expand-function type) k source)))
- (cond
- ((symbolp v)
- (list (list v getter)))
- (t (dash--match v getter)))))
- (-partition 2 match-form))))
-
-(defun dash--match-symbol (match-form source)
- "Bind a symbol.
-
-This works just like `let', there is no destructuring."
- (list (list match-form source)))
-
-(defun dash--match (match-form source)
- "Match MATCH-FORM against SOURCE.
-
-This function tests the MATCH-FORM and dispatches to specific
-matchers based on the type of the expression.
-
-Key-value stores are disambiguated by placing a token &plist,
-&alist or &hash as a first item in the MATCH-FORM."
- (cond
- ((symbolp match-form)
- (dash--match-symbol match-form source))
- ((consp match-form)
- (cond
- ;; Handle the "x &as" bindings first.
- ((and (consp (cdr match-form))
- (symbolp (car match-form))
- (eq '&as (cadr match-form)))
- (let ((s (car match-form)))
- (cons (list s source)
- (dash--match (cddr match-form) s))))
- ((functionp (dash--get-expand-function (car match-form)))
- (dash--match-kv (dash--match-kv-normalize-match-form match-form) source))
- (t (dash--match-cons match-form source))))
- ((vectorp match-form)
- ;; We support the &as binding in vectors too
- (cond
- ((and (> (length match-form) 2)
- (symbolp (aref match-form 0))
- (eq '&as (aref match-form 1)))
- (let ((s (aref match-form 0)))
- (cons (list s source)
- (dash--match (dash--vector-tail match-form 2) s))))
- (t (dash--match-vector match-form source))))))
-
-(defun dash--normalize-let-varlist (varlist)
- "Normalize VARLIST so that every binding is a list.
-
-`let' allows specifying a binding which is not a list but simply
-the place which is then automatically bound to nil, such that all
-three of the following are identical and evaluate to nil.
-
- (let (a) a)
- (let ((a)) a)
- (let ((a nil)) a)
-
-This function normalizes all of these to the last form."
- (--map (if (consp it) it (list it nil)) varlist))
-
-(defmacro -let* (varlist &rest body)
- "Bind variables according to VARLIST then eval BODY.
-
-VARLIST is a list of lists of the form (PATTERN SOURCE). Each
-PATTERN is matched against the SOURCE structurally. SOURCE is
-only evaluated once for each PATTERN.
-
-Each SOURCE can refer to the symbols already bound by this
-VARLIST. This is useful if you want to destructure SOURCE
-recursively but also want to name the intermediate structures.
-
-See `-let' for the list of all possible patterns."
- (declare (debug ((&rest [&or (sexp form) sexp]) body))
- (indent 1))
- (let* ((varlist (dash--normalize-let-varlist varlist))
- (bindings (--mapcat (dash--match (car it) (cadr it)) varlist)))
- `(let* ,bindings
- ,@body)))
-
-(defmacro -let (varlist &rest body)
- "Bind variables according to VARLIST then eval BODY.
-
-VARLIST is a list of lists of the form (PATTERN SOURCE). Each
-PATTERN is matched against the SOURCE \"structurally\". SOURCE
-is only evaluated once for each PATTERN. Each PATTERN is matched
-recursively, and can therefore contain sub-patterns which are
-matched against corresponding sub-expressions of SOURCE.
-
-All the SOURCEs are evalled before any symbols are
-bound (i.e. \"in parallel\").
-
-If VARLIST only contains one (PATTERN SOURCE) element, you can
-optionally specify it using a vector and discarding the
-outer-most parens. Thus
-
- (-let ((PATTERN SOURCE)) ..)
-
-becomes
-
- (-let [PATTERN SOURCE] ..).
-
-`-let' uses a convention of not binding places (symbols) starting
-with _ whenever it's possible. You can use this to skip over
-entries you don't care about. However, this is not *always*
-possible (as a result of implementation) and these symbols might
-get bound to undefined values.
-
-Following is the overview of supported patterns. Remember that
-patterns can be matched recursively, so every a, b, aK in the
-following can be a matching construct and not necessarily a
-symbol/variable.
-
-Symbol:
-
- a - bind the SOURCE to A. This is just like regular `let'.
-
-Conses and lists:
-
- (a) - bind `car' of cons/list to A
-
- (a . b) - bind car of cons to A and `cdr' to B
-
- (a b) - bind car of list to A and `cadr' to B
-
- (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ...
-
- (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST.
-
-Vectors:
-
- [a] - bind 0th element of a non-list sequence to A (works with
- vectors, strings, bit arrays...)
-
- [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to
- A1, 2nd to A2, ...
- If the PATTERN is shorter than SOURCE, the values at
- places not in PATTERN are ignored.
- If the PATTERN is longer than SOURCE, an `error' is
- thrown.
-
- [a1 a2 a3 ... &rest rest] - as above, but bind the rest of
- the sequence to REST. This is
- conceptually the same as improper list
- matching (a1 a2 ... aN . rest)
-
-Key/value stores:
-
- (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE plist to aK. If the
- value is not found, aK is nil.
- Uses `plist-get' to fetch values.
-
- (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE alist to aK. If the
- value is not found, aK is nil.
- Uses `assoc' to fetch values.
-
- (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE hash table to aK. If the
- value is not found, aK is nil.
- Uses `gethash' to fetch values.
-
-Further, special keyword &keys supports \"inline\" matching of
-plist-like key-value pairs, similarly to &keys keyword of
-`cl-defun'.
-
- (a1 a2 ... aN &keys key1 b1 ... keyN bK)
-
-This binds N values from the list to a1 ... aN, then interprets
-the cdr as a plist (see key/value matching above).
-
-A shorthand notation for kv-destructuring exists which allows the
-patterns be optionally left out and derived from the key name in
-the following fashion:
-
-- a key :foo is converted into `foo' pattern,
-- a key 'bar is converted into `bar' pattern,
-- a key \"baz\" is converted into `baz' pattern.
-
-That is, the entire value under the key is bound to the derived
-variable without any further destructuring.
-
-This is possible only when the form following the key is not a
-valid pattern (i.e. not a symbol, a cons cell or a vector).
-Otherwise the matching proceeds as usual and in case of an
-invalid spec fails with an error.
-
-Thus the patterns are normalized as follows:
-
- ;; derive all the missing patterns
- (&plist :foo 'bar \"baz\") => (&plist :foo foo 'bar bar \"baz\" baz)
-
- ;; we can specify some but not others
- (&plist :foo 'bar explicit-bar) => (&plist :foo foo 'bar explicit-bar)
-
- ;; nothing happens, we store :foo in x
- (&plist :foo x) => (&plist :foo x)
-
- ;; nothing happens, we match recursively
- (&plist :foo (a b c)) => (&plist :foo (a b c))
-
-You can name the source using the syntax SYMBOL &as PATTERN.
-This syntax works with lists (proper or improper), vectors and
-all types of maps.
-
- (list &as a b c) (list 1 2 3)
-
-binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
-
-Similarly:
-
- (bounds &as beg . end) (cons 1 2)
-
-binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
-
- (items &as first . rest) (list 1 2 3)
-
-binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
-
- [vect &as _ b c] [1 2 3]
-
-binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual).
-
- (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
-
-binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash.
-
-This is especially useful when we want to capture the result of a
-computation and destructure at the same time. Consider the
-form (function-returning-complex-structure) returning a list of
-two vectors with two items each. We want to capture this entire
-result and pass it to another computation, but at the same time
-we want to get the second item from each vector. We can achieve
-it with pattern
-
- (result &as [_ a] [_ b]) (function-returning-complex-structure)
-
-Note: Clojure programmers may know this feature as the \":as
-binding\". The difference is that we put the &as at the front
-because we need to support improper list binding."
- (declare (debug ([&or (&rest [&or (sexp form) sexp])
- (vector [&rest [sexp form]])]
- body))
- (indent 1))
- (if (vectorp varlist)
- `(let* ,(dash--match (aref varlist 0) (aref varlist 1))
- ,@body)
- (let* ((varlist (dash--normalize-let-varlist varlist))
- (inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist))
- (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs))))
- `(let ,inputs
- (-let* ,new-varlist ,@body)))))
-
-(defmacro -lambda (match-form &rest body)
- "Return a lambda which destructures its input as MATCH-FORM and executes BODY.
-
-Note that you have to enclose the MATCH-FORM in a pair of parens,
-such that:
-
- (-lambda (x) body)
- (-lambda (x y ...) body)
-
-has the usual semantics of `lambda'. Furthermore, these get
-translated into normal lambda, so there is no performance
-penalty.
-
-See `-let' for the description of destructuring mechanism."
- (declare (doc-string 2) (indent defun)
- (debug (&define sexp
- [&optional stringp]
- [&optional ("interactive" interactive)]
- def-body)))
- (cond
- ((not (consp match-form))
- (signal 'wrong-type-argument "match-form must be a list"))
- ;; no destructuring, so just return regular lambda to make things faster
- ((-all? 'symbolp match-form)
- `(lambda ,match-form ,@body))
- (t
- (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form)))
- ;; TODO: because inputs to the lambda are evaluated only once,
- ;; -let* need not to create the extra bindings to ensure that.
- ;; We should find a way to optimize that. Not critical however.
- `(lambda ,(--map (cadr it) inputs)
- (-let* ,inputs ,@body))))))
-
-(defmacro -setq (&rest forms)
- "Bind each MATCH-FORM to the value of its VAL.
-
-MATCH-FORM destructuring is done according to the rules of `-let'.
-
-This macro allows you to bind multiple variables by destructuring
-the value, so for example:
-
- (-setq (a b) x
- (&plist :c c) plist)
-
-expands roughly speaking to the following code
-
- (setq a (car x)
- b (cadr x)
- c (plist-get plist :c))
-
-Care is taken to only evaluate each VAL once so that in case of
-multiple assignments it does not cause unexpected side effects.
-
-\(fn [MATCH-FORM VAL]...)"
- (declare (debug (&rest sexp form))
- (indent 1))
- (when (= (mod (length forms) 2) 1)
- (error "Odd number of arguments"))
- (let* ((forms-and-sources
- ;; First get all the necessary mappings with all the
- ;; intermediate bindings.
- (-map (lambda (x) (dash--match (car x) (cadr x)))
- (-partition 2 forms)))
- ;; To preserve the logic of dynamic scoping we must ensure
- ;; that we `setq' the variables outside of the `let*' form
- ;; which holds the destructured intermediate values. For
- ;; this we generate for each variable a placeholder which is
- ;; bound to (lexically) the result of the destructuring.
- ;; Then outside of the helper `let*' form we bind all the
- ;; original variables to their respective placeholders.
- ;; TODO: There is a lot of room for possible optimization,
- ;; for start playing with `special-variable-p' to eliminate
- ;; unnecessary re-binding.
- (variables-to-placeholders
- (-mapcat
- (lambda (bindings)
- (-map
- (lambda (binding)
- (let ((var (car binding)))
- (list var (make-symbol (concat "--dash-binding-" (symbol-name var) "--")))))
- (--filter (not (string-prefix-p "--" (symbol-name (car it)))) bindings)))
- forms-and-sources)))
- `(let ,(-map 'cadr variables-to-placeholders)
- (let* ,(-flatten-n 1 forms-and-sources)
- (setq ,@(-flatten (-map 'reverse variables-to-placeholders))))
- (setq ,@(-flatten variables-to-placeholders)))))
-
-(defmacro -if-let* (vars-vals then &rest else)
- "If all VALS evaluate to true, bind them to their corresponding
-VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list
-of (VAR VAL) pairs.
-
-Note: binding is done according to `-let*'. VALS are evaluated
-sequentially, and evaluation stops after the first nil VAL is
-encountered."
- (declare (debug ((&rest (sexp form)) form body))
- (indent 2))
- (->> vars-vals
- (--mapcat (dash--match (car it) (cadr it)))
- (--reduce-r-from
- (let ((var (car it))
- (val (cadr it)))
- `(let ((,var ,val))
- (if ,var ,acc ,@else)))
- then)))
-
-(defmacro -if-let (var-val then &rest else)
- "If VAL evaluates to non-nil, bind it to VAR and do THEN,
-otherwise do ELSE.
-
-Note: binding is done according to `-let'.
-
-\(fn (VAR VAL) THEN &rest ELSE)"
- (declare (debug ((sexp form) form body))
- (indent 2))
- `(-if-let* (,var-val) ,then ,@else))
-
-(defmacro --if-let (val then &rest else)
- "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN,
-otherwise do ELSE."
- (declare (debug (form form body))
- (indent 2))
- `(-if-let (it ,val) ,then ,@else))
-
-(defmacro -when-let* (vars-vals &rest body)
- "If all VALS evaluate to true, bind them to their corresponding
-VARS and execute body. VARS-VALS should be a list of (VAR VAL)
-pairs.
-
-Note: binding is done according to `-let*'. VALS are evaluated
-sequentially, and evaluation stops after the first nil VAL is
-encountered."
- (declare (debug ((&rest (sexp form)) body))
- (indent 1))
- `(-if-let* ,vars-vals (progn ,@body)))
-
-(defmacro -when-let (var-val &rest body)
- "If VAL evaluates to non-nil, bind it to VAR and execute body.
-
-Note: binding is done according to `-let'.
-
-\(fn (VAR VAL) &rest BODY)"
- (declare (debug ((sexp form) body))
- (indent 1))
- `(-if-let ,var-val (progn ,@body)))
-
-(defmacro --when-let (val &rest body)
- "If VAL evaluates to non-nil, bind it to symbol `it' and
-execute body."
- (declare (debug (form body))
- (indent 1))
- `(--if-let ,val (progn ,@body)))
-
-(defvar -compare-fn nil
- "Tests for equality use this function or `equal' if this is nil.
-It should only be set using dynamic scope with a let, like:
-
- (let ((-compare-fn #\\='=)) (-union numbers1 numbers2 numbers3)")
-
-(defun -distinct (list)
- "Return a new list with all duplicates removed.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil.
-
-Alias: `-uniq'"
- ;; Implementation note: The speedup gained from hash table lookup
- ;; starts to outweigh its overhead for lists of length greater than
- ;; 32. See discussion in PR #305.
- (let* ((len (length list))
- (lut (and (> len 32)
- ;; Check that `-compare-fn' is a valid hash-table
- ;; lookup function or `nil'.
- (memq -compare-fn '(nil equal eq eql))
- (make-hash-table :test (or -compare-fn #'equal)
- :size len))))
- (if lut
- (--filter (unless (gethash it lut)
- (puthash it t lut))
- list)
- (--each list (unless (-contains? lut it) (!cons it lut)))
- (nreverse lut))))
-
-(defalias '-uniq '-distinct)
-
-(defun -union (list list2)
- "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil."
- ;; We fall back to iteration implementation if the comparison
- ;; function isn't one of `eq', `eql' or `equal'.
- (let* ((result (reverse list))
- ;; TODO: get rid of this dynamic variable, pass it as an
- ;; argument instead.
- (-compare-fn (if (bound-and-true-p -compare-fn)
- -compare-fn
- 'equal)))
- (if (memq -compare-fn '(eq eql equal))
- (let ((ht (make-hash-table :test -compare-fn)))
- (--each list (puthash it t ht))
- (--each list2 (unless (gethash it ht) (!cons it result))))
- (--each list2 (unless (-contains? result it) (!cons it result))))
- (nreverse result)))
-
-(defun -intersection (list list2)
- "Return a new list containing only the elements that are members of both LIST and LIST2.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil."
- (--filter (-contains? list2 it) list))
-
-(defun -difference (list list2)
- "Return a new list with only the members of LIST that are not in LIST2.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil."
- (--filter (not (-contains? list2 it)) list))
-
-(defun -powerset (list)
- "Return the power set of LIST."
- (if (null list) '(())
- (let ((last (-powerset (cdr list))))
- (append (mapcar (lambda (x) (cons (car list) x)) last)
- last))))
-
-(defun -permutations (list)
- "Return the permutations of LIST."
- (if (null list) '(())
- (apply #'append
- (mapcar (lambda (x)
- (mapcar (lambda (perm) (cons x perm))
- (-permutations (remove x list))))
- list))))
-
-(defun -inits (list)
- "Return all prefixes of LIST."
- (let ((res (list list)))
- (setq list (reverse list))
- (while list
- (push (reverse (!cdr list)) res))
- res))
-
-(defun -tails (list)
- "Return all suffixes of LIST"
- (-reductions-r-from 'cons nil list))
-
-(defun -common-prefix (&rest lists)
- "Return the longest common prefix of LISTS."
- (declare (pure t) (side-effect-free t))
- (--reduce (--take-while (and acc (equal (pop acc) it)) it)
- lists))
-
-(defun -common-suffix (&rest lists)
- "Return the longest common suffix of LISTS."
- (nreverse (apply #'-common-prefix (mapcar #'reverse lists))))
-
-(defun -contains? (list element)
- "Return non-nil if LIST contains ELEMENT.
-
-The test for equality is done with `equal', or with `-compare-fn'
-if that's non-nil.
-
-Alias: `-contains-p'"
- (not
- (null
- (cond
- ((null -compare-fn) (member element list))
- ((eq -compare-fn 'eq) (memq element list))
- ((eq -compare-fn 'eql) (memql element list))
- (t
- (let ((lst list))
- (while (and lst
- (not (funcall -compare-fn element (car lst))))
- (setq lst (cdr lst)))
- lst))))))
-
-(defalias '-contains-p '-contains?)
-
-(defun -same-items? (list list2)
- "Return true if LIST and LIST2 has the same items.
-
-The order of the elements in the lists does not matter.
-
-Alias: `-same-items-p'"
- (let ((length-a (length list))
- (length-b (length list2)))
- (and
- (= length-a length-b)
- (= length-a (length (-intersection list list2))))))
-
-(defalias '-same-items-p '-same-items?)
-
-(defun -is-prefix? (prefix list)
- "Return non-nil if PREFIX is prefix of LIST.
-
-Alias: `-is-prefix-p'"
- (declare (pure t) (side-effect-free t))
- (--each-while list (equal (car prefix) it)
- (!cdr prefix))
- (not prefix))
-
-(defun -is-suffix? (suffix list)
- "Return non-nil if SUFFIX is suffix of LIST.
-
-Alias: `-is-suffix-p'"
- (declare (pure t) (side-effect-free t))
- (-is-prefix? (reverse suffix) (reverse list)))
-
-(defun -is-infix? (infix list)
- "Return non-nil if INFIX is infix of LIST.
-
-This operation runs in O(n^2) time
-
-Alias: `-is-infix-p'"
- (declare (pure t) (side-effect-free t))
- (let (done)
- (while (and (not done) list)
- (setq done (-is-prefix? infix list))
- (!cdr list))
- done))
-
-(defalias '-is-prefix-p '-is-prefix?)
-(defalias '-is-suffix-p '-is-suffix?)
-(defalias '-is-infix-p '-is-infix?)
-
-(defun -sort (comparator list)
- "Sort LIST, stably, comparing elements using COMPARATOR.
-Return the sorted list. LIST is NOT modified by side effects.
-COMPARATOR is called with two elements of LIST, and should return non-nil
-if the first element should sort before the second."
- (sort (copy-sequence list) comparator))
-
-(defmacro --sort (form list)
- "Anaphoric form of `-sort'."
- (declare (debug (form form)))
- `(-sort (lambda (it other) ,form) ,list))
-
-(defun -list (&rest args)
- "Return a list with ARGS.
-
-If first item of ARGS is already a list, simply return ARGS. If
-not, return a list with ARGS as elements."
- (declare (pure t) (side-effect-free t))
- (let ((arg (car args)))
- (if (listp arg) arg args)))
-
-(defun -repeat (n x)
- "Return a list with X repeated N times.
-Return nil if N is less than 1."
- (declare (pure t) (side-effect-free t))
- (let (ret)
- (--dotimes n (!cons x ret))
- ret))
-
-(defun -sum (list)
- "Return the sum of LIST."
- (declare (pure t) (side-effect-free t))
- (apply '+ list))
-
-(defun -running-sum (list)
- "Return a list with running sums of items in LIST.
-
-LIST must be non-empty."
- (declare (pure t) (side-effect-free t))
- (unless (consp list)
- (error "LIST must be non-empty"))
- (-reductions '+ list))
-
-(defun -product (list)
- "Return the product of LIST."
- (declare (pure t) (side-effect-free t))
- (apply '* list))
-
-(defun -running-product (list)
- "Return a list with running products of items in LIST.
-
-LIST must be non-empty."
- (declare (pure t) (side-effect-free t))
- (unless (consp list)
- (error "LIST must be non-empty"))
- (-reductions '* list))
-
-(defun -max (list)
- "Return the largest value from LIST of numbers or markers."
- (declare (pure t) (side-effect-free t))
- (apply 'max list))
-
-(defun -min (list)
- "Return the smallest value from LIST of numbers or markers."
- (declare (pure t) (side-effect-free t))
- (apply 'min list))
-
-(defun -max-by (comparator list)
- "Take a comparison function COMPARATOR and a LIST and return
-the greatest element of the list by the comparison function.
-
-See also combinator `-on' which can transform the values before
-comparing them."
- (--reduce (if (funcall comparator it acc) it acc) list))
-
-(defun -min-by (comparator list)
- "Take a comparison function COMPARATOR and a LIST and return
-the least element of the list by the comparison function.
-
-See also combinator `-on' which can transform the values before
-comparing them."
- (--reduce (if (funcall comparator it acc) acc it) list))
-
-(defmacro --max-by (form list)
- "Anaphoric version of `-max-by'.
-
-The items for the comparator form are exposed as \"it\" and \"other\"."
- (declare (debug (form form)))
- `(-max-by (lambda (it other) ,form) ,list))
-
-(defmacro --min-by (form list)
- "Anaphoric version of `-min-by'.
-
-The items for the comparator form are exposed as \"it\" and \"other\"."
- (declare (debug (form form)))
- `(-min-by (lambda (it other) ,form) ,list))
-
-(defun -iterate (fun init n)
- "Return a list of iterated applications of FUN to INIT.
-
-This means a list of form:
-
- (init (fun init) (fun (fun init)) ...)
-
-N is the length of the returned list."
- (if (= n 0) nil
- (let ((r (list init)))
- (--dotimes (1- n)
- (push (funcall fun (car r)) r))
- (nreverse r))))
-
-(defun -fix (fn list)
- "Compute the (least) fixpoint of FN with initial input LIST.
-
-FN is called at least once, results are compared with `equal'."
- (let ((re (funcall fn list)))
- (while (not (equal list re))
- (setq list re)
- (setq re (funcall fn re)))
- re))
-
-(defmacro --fix (form list)
- "Anaphoric form of `-fix'."
- `(-fix (lambda (it) ,form) ,list))
-
-(defun -unfold (fun seed)
- "Build a list from SEED using FUN.
-
-This is \"dual\" operation to `-reduce-r': while -reduce-r
-consumes a list to produce a single value, `-unfold' takes a
-seed value and builds a (potentially infinite!) list.
-
-FUN should return `nil' to stop the generating process, or a
-cons (A . B), where A will be prepended to the result and B is
-the new seed."
- (let ((last (funcall fun seed)) r)
- (while last
- (push (car last) r)
- (setq last (funcall fun (cdr last))))
- (nreverse r)))
-
-(defmacro --unfold (form seed)
- "Anaphoric version of `-unfold'."
- (declare (debug (form form)))
- `(-unfold (lambda (it) ,form) ,seed))
-
-(defun -cons-pair? (con)
- "Return non-nil if CON is true cons pair.
-That is (A . B) where B is not a list.
-
-Alias: `-cons-pair-p'"
- (declare (pure t) (side-effect-free t))
- (and (listp con)
- (not (listp (cdr con)))))
-
-(defalias '-cons-pair-p '-cons-pair?)
-
-(defun -cons-to-list (con)
- "Convert a cons pair to a list with `car' and `cdr' of the pair respectively."
- (declare (pure t) (side-effect-free t))
- (list (car con) (cdr con)))
-
-(defun -value-to-list (val)
- "Convert a value to a list.
-
-If the value is a cons pair, make a list with two elements, `car'
-and `cdr' of the pair respectively.
-
-If the value is anything else, wrap it in a list."
- (declare (pure t) (side-effect-free t))
- (cond
- ((-cons-pair? val) (-cons-to-list val))
- (t (list val))))
-
-(defun -tree-mapreduce-from (fn folder init-value tree)
- "Apply FN to each element of TREE, and make a list of the results.
-If elements of TREE are lists themselves, apply FN recursively to
-elements of these nested lists.
-
-Then reduce the resulting lists using FOLDER and initial value
-INIT-VALUE. See `-reduce-r-from'.
-
-This is the same as calling `-tree-reduce-from' after `-tree-map'
-but is twice as fast as it only traverse the structure once."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) (funcall fn tree))
- ((listp tree)
- (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree)))
- (t (funcall fn tree))))
-
-(defmacro --tree-mapreduce-from (form folder init-value tree)
- "Anaphoric form of `-tree-mapreduce-from'."
- (declare (debug (form form form form)))
- `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree))
-
-(defun -tree-mapreduce (fn folder tree)
- "Apply FN to each element of TREE, and make a list of the results.
-If elements of TREE are lists themselves, apply FN recursively to
-elements of these nested lists.
-
-Then reduce the resulting lists using FOLDER and initial value
-INIT-VALUE. See `-reduce-r-from'.
-
-This is the same as calling `-tree-reduce' after `-tree-map'
-but is twice as fast as it only traverse the structure once."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) (funcall fn tree))
- ((listp tree)
- (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree)))
- (t (funcall fn tree))))
-
-(defmacro --tree-mapreduce (form folder tree)
- "Anaphoric form of `-tree-mapreduce'."
- (declare (debug (form form form)))
- `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree))
-
-(defun -tree-map (fn tree)
- "Apply FN to each element of TREE while preserving the tree structure."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) (funcall fn tree))
- ((listp tree)
- (mapcar (lambda (x) (-tree-map fn x)) tree))
- (t (funcall fn tree))))
-
-(defmacro --tree-map (form tree)
- "Anaphoric form of `-tree-map'."
- (declare (debug (form form)))
- `(-tree-map (lambda (it) ,form) ,tree))
-
-(defun -tree-reduce-from (fn init-value tree)
- "Use FN to reduce elements of list TREE.
-If elements of TREE are lists themselves, apply the reduction recursively.
-
-FN is first applied to INIT-VALUE and first element of the list,
-then on this result and second element from the list etc.
-
-The initial value is ignored on cons pairs as they always contain
-two elements."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) tree)
- ((listp tree)
- (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree)))
- (t tree)))
-
-(defmacro --tree-reduce-from (form init-value tree)
- "Anaphoric form of `-tree-reduce-from'."
- (declare (debug (form form form)))
- `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree))
-
-(defun -tree-reduce (fn tree)
- "Use FN to reduce elements of list TREE.
-If elements of TREE are lists themselves, apply the reduction recursively.
-
-FN is first applied to first element of the list and second
-element, then on this result and third element from the list etc.
-
-See `-reduce-r' for how exactly are lists of zero or one element handled."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) tree)
- ((listp tree)
- (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree)))
- (t tree)))
-
-(defmacro --tree-reduce (form tree)
- "Anaphoric form of `-tree-reduce'."
- (declare (debug (form form)))
- `(-tree-reduce (lambda (it acc) ,form) ,tree))
-
-(defun -tree-map-nodes (pred fun tree)
- "Call FUN on each node of TREE that satisfies PRED.
-
-If PRED returns nil, continue descending down this node. If PRED
-returns non-nil, apply FUN to this node and do not descend
-further."
- (if (funcall pred tree)
- (funcall fun tree)
- (if (and (listp tree)
- (not (-cons-pair? tree)))
- (-map (lambda (x) (-tree-map-nodes pred fun x)) tree)
- tree)))
-
-(defmacro --tree-map-nodes (pred form tree)
- "Anaphoric form of `-tree-map-nodes'."
- `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree))
-
-(defun -tree-seq (branch children tree)
- "Return a sequence of the nodes in TREE, in depth-first search order.
-
-BRANCH is a predicate of one argument that returns non-nil if the
-passed argument is a branch, that is, a node that can have children.
-
-CHILDREN is a function of one argument that returns the children
-of the passed branch node.
-
-Non-branch nodes are simply copied."
- (cons tree
- (when (funcall branch tree)
- (-mapcat (lambda (x) (-tree-seq branch children x))
- (funcall children tree)))))
-
-(defmacro --tree-seq (branch children tree)
- "Anaphoric form of `-tree-seq'."
- `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree))
-
-(defun -clone (list)
- "Create a deep copy of LIST.
-The new list has the same elements and structure but all cons are
-replaced with new ones. This is useful when you need to clone a
-structure such as plist or alist."
- (declare (pure t) (side-effect-free t))
- (-tree-map 'identity list))
-
-(defun dash-enable-font-lock ()
- "Add syntax highlighting to dash functions, macros and magic values."
- (eval-after-load 'lisp-mode
- '(progn
- (let ((new-keywords '(
- "!cons"
- "!cdr"
- "-each"
- "--each"
- "-each-indexed"
- "--each-indexed"
- "-each-while"
- "--each-while"
- "-doto"
- "-dotimes"
- "--dotimes"
- "-map"
- "--map"
- "-reduce-from"
- "--reduce-from"
- "-reduce"
- "--reduce"
- "-reduce-r-from"
- "--reduce-r-from"
- "-reduce-r"
- "--reduce-r"
- "-reductions-from"
- "-reductions-r-from"
- "-reductions"
- "-reductions-r"
- "-filter"
- "--filter"
- "-select"
- "--select"
- "-remove"
- "--remove"
- "-reject"
- "--reject"
- "-remove-first"
- "--remove-first"
- "-reject-first"
- "--reject-first"
- "-remove-last"
- "--remove-last"
- "-reject-last"
- "--reject-last"
- "-remove-item"
- "-non-nil"
- "-keep"
- "--keep"
- "-map-indexed"
- "--map-indexed"
- "-splice"
- "--splice"
- "-splice-list"
- "--splice-list"
- "-map-when"
- "--map-when"
- "-replace-where"
- "--replace-where"
- "-map-first"
- "--map-first"
- "-map-last"
- "--map-last"
- "-replace"
- "-replace-first"
- "-replace-last"
- "-flatten"
- "-flatten-n"
- "-concat"
- "-mapcat"
- "--mapcat"
- "-copy"
- "-cons*"
- "-snoc"
- "-first"
- "--first"
- "-find"
- "--find"
- "-some"
- "--some"
- "-any"
- "--any"
- "-last"
- "--last"
- "-first-item"
- "-second-item"
- "-third-item"
- "-fourth-item"
- "-fifth-item"
- "-last-item"
- "-butlast"
- "-count"
- "--count"
- "-any?"
- "--any?"
- "-some?"
- "--some?"
- "-any-p"
- "--any-p"
- "-some-p"
- "--some-p"
- "-some->"
- "-some->>"
- "-some-->"
- "-all?"
- "-all-p"
- "--all?"
- "--all-p"
- "-every?"
- "--every?"
- "-all-p"
- "--all-p"
- "-every-p"
- "--every-p"
- "-none?"
- "--none?"
- "-none-p"
- "--none-p"
- "-only-some?"
- "--only-some?"
- "-only-some-p"
- "--only-some-p"
- "-slice"
- "-take"
- "-drop"
- "-drop-last"
- "-take-last"
- "-take-while"
- "--take-while"
- "-drop-while"
- "--drop-while"
- "-split-at"
- "-rotate"
- "-insert-at"
- "-replace-at"
- "-update-at"
- "--update-at"
- "-remove-at"
- "-remove-at-indices"
- "-split-with"
- "--split-with"
- "-split-on"
- "-split-when"
- "--split-when"
- "-separate"
- "--separate"
- "-partition-all-in-steps"
- "-partition-in-steps"
- "-partition-all"
- "-partition"
- "-partition-after-item"
- "-partition-after-pred"
- "-partition-before-item"
- "-partition-before-pred"
- "-partition-by"
- "--partition-by"
- "-partition-by-header"
- "--partition-by-header"
- "-group-by"
- "--group-by"
- "-interpose"
- "-interleave"
- "-unzip"
- "-zip-with"
- "--zip-with"
- "-zip"
- "-zip-fill"
- "-zip-lists"
- "-zip-pair"
- "-cycle"
- "-pad"
- "-annotate"
- "--annotate"
- "-table"
- "-table-flat"
- "-partial"
- "-elem-index"
- "-elem-indices"
- "-find-indices"
- "--find-indices"
- "-find-index"
- "--find-index"
- "-find-last-index"
- "--find-last-index"
- "-select-by-indices"
- "-select-columns"
- "-select-column"
- "-grade-up"
- "-grade-down"
- "->"
- "->>"
- "-->"
- "-as->"
- "-when-let"
- "-when-let*"
- "--when-let"
- "-if-let"
- "-if-let*"
- "--if-let"
- "-let*"
- "-let"
- "-lambda"
- "-distinct"
- "-uniq"
- "-union"
- "-intersection"
- "-difference"
- "-powerset"
- "-permutations"
- "-inits"
- "-tails"
- "-common-prefix"
- "-common-suffix"
- "-contains?"
- "-contains-p"
- "-same-items?"
- "-same-items-p"
- "-is-prefix-p"
- "-is-prefix?"
- "-is-suffix-p"
- "-is-suffix?"
- "-is-infix-p"
- "-is-infix?"
- "-sort"
- "--sort"
- "-list"
- "-repeat"
- "-sum"
- "-running-sum"
- "-product"
- "-running-product"
- "-max"
- "-min"
- "-max-by"
- "--max-by"
- "-min-by"
- "--min-by"
- "-iterate"
- "--iterate"
- "-fix"
- "--fix"
- "-unfold"
- "--unfold"
- "-cons-pair?"
- "-cons-pair-p"
- "-cons-to-list"
- "-value-to-list"
- "-tree-mapreduce-from"
- "--tree-mapreduce-from"
- "-tree-mapreduce"
- "--tree-mapreduce"
- "-tree-map"
- "--tree-map"
- "-tree-reduce-from"
- "--tree-reduce-from"
- "-tree-reduce"
- "--tree-reduce"
- "-tree-seq"
- "--tree-seq"
- "-tree-map-nodes"
- "--tree-map-nodes"
- "-clone"
- "-rpartial"
- "-juxt"
- "-applify"
- "-on"
- "-flip"
- "-const"
- "-cut"
- "-orfn"
- "-andfn"
- "-iteratefn"
- "-fixfn"
- "-prodfn"
- ))
- (special-variables '(
- "it"
- "it-index"
- "acc"
- "other"
- )))
- (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>")
- 1 font-lock-variable-name-face)) 'append)
- (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>")
- 1 font-lock-keyword-face)) 'append))
- (--each (buffer-list)
- (with-current-buffer it
- (when (and (eq major-mode 'emacs-lisp-mode)
- (boundp 'font-lock-mode)
- font-lock-mode)
- (font-lock-refresh-defaults)))))))
-
-(provide 'dash)
-;;; dash.el ends here
+++ /dev/null
-This is dash.info, produced by makeinfo version 6.5 from dash.texi.
-
-This manual is for ‘dash.el’ version 2.12.1.
-
- Copyright © 2012-2015 Magnar Sveen
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see
- <http://www.gnu.org/licenses/>.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Dash: (dash.info). A modern list library for GNU Emacs
-END-INFO-DIR-ENTRY
-
-\1f
-File: dash.info, Node: Top, Next: Installation, Up: (dir)
-
-dash
-****
-
-This manual is for ‘dash.el’ version 2.12.1.
-
- Copyright © 2012-2015 Magnar Sveen
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see
- <http://www.gnu.org/licenses/>.
-
-* Menu:
-
-* Installation::
-* Functions::
-* Development::
-* Index::
-
-— The Detailed Node Listing —
-
-Installation
-
-* Using in a package::
-* Syntax highlighting of dash functions::
-
-Functions
-
-* Maps::
-* Sublist selection::
-* List to list::
-* Reductions::
-* Unfolding::
-* Predicates::
-* Partitioning::
-* Indexing::
-* Set operations::
-* Other list operations::
-* Tree operations::
-* Threading macros::
-* Binding::
-* Side-effects::
-* Destructive operations::
-* Function combinators::
-
-Development
-
-* Contribute:: How to contribute
-* Changes:: List of significant changes by version
-* Contributors:: List of contributors
-
-\1f
-File: dash.info, Node: Installation, Next: Functions, Prev: Top, Up: Top
-
-1 Installation
-**************
-
-It’s available on Melpa (https://melpa.org/); use ‘M-x package-install’:
-
-‘M-x package-install <RET> dash’
- Install the dash library.
-
-‘M-x package-install <RET> dash-functional’
- Optional, if you want the function combinators.
-
- Alternatively, you can just dump dash.el or dash-functional.el in
-your load path somewhere.
-
-* Menu:
-
-* Using in a package::
-* Syntax highlighting of dash functions::
-
-\1f
-File: dash.info, Node: Using in a package, Next: Syntax highlighting of dash functions, Up: Installation
-
-1.1 Using in a package
-======================
-
-Add this to the big comment block at the top:
-
- ;; Package-Requires: ((dash "2.12.1"))
-
-To get function combinators:
-
- ;; Package-Requires: ((dash "2.12.1") (dash-functional "1.2.0") (emacs "24"))
-
-\1f
-File: dash.info, Node: Syntax highlighting of dash functions, Prev: Using in a package, Up: Installation
-
-1.2 Syntax highlighting of dash functions
-=========================================
-
-Font lock of dash functions in emacs lisp buffers is now optional.
-Include this in your emacs settings to get syntax highlighting:
-
- (eval-after-load 'dash '(dash-enable-font-lock))
-
-\1f
-File: dash.info, Node: Functions, Next: Development, Prev: Installation, Up: Top
-
-2 Functions
-***********
-
-This chapter contains reference documentation for the dash application
-programming interface (API). All functions and constructs in the library
-are prefixed with a dash (-).
-
- There are also anaphoric versions of functions where that makes
-sense, prefixed with two dashes instead of one.
-
- For instance, while ‘-map’ takes a function to map over the list, one
-can also use the anaphoric form with double dashes - which will then be
-executed with ‘it’ exposed as the list item. Here’s an example:
-
- (-map (lambda (n) (* n n)) '(1 2 3 4)) ;; normal version
-
- (--map (* it it) '(1 2 3 4)) ;; anaphoric version
-
-Of course, the original can also be written like
-
- (defun square (n) (* n n))
-
- (-map 'square '(1 2 3 4))
-
-which demonstrates the usefulness of both versions.
-
-* Menu:
-
-* Maps::
-* Sublist selection::
-* List to list::
-* Reductions::
-* Unfolding::
-* Predicates::
-* Partitioning::
-* Indexing::
-* Set operations::
-* Other list operations::
-* Tree operations::
-* Threading macros::
-* Binding::
-* Side-effects::
-* Destructive operations::
-* Function combinators::
-
-\1f
-File: dash.info, Node: Maps, Next: Sublist selection, Up: Functions
-
-2.1 Maps
-========
-
-Functions in this category take a transforming function, which is then
-applied sequentially to each or selected elements of the input list.
-The results are collected in order and returned as new list.
-
- -- Function: -map (fn list)
- Return a new list consisting of the result of applying FN to the
- items in LIST.
-
- (-map (lambda (num) (* num num)) '(1 2 3 4))
- ⇒ '(1 4 9 16)
- (-map 'square '(1 2 3 4))
- ⇒ '(1 4 9 16)
- (--map (* it it) '(1 2 3 4))
- ⇒ '(1 4 9 16)
-
- -- Function: -map-when (pred rep list)
- Return a new list where the elements in LIST that do not match the
- PRED function are unchanged, and where the elements in LIST that do
- match the PRED function are mapped through the REP function.
-
- Alias: ‘-replace-where’
-
- See also: ‘-update-at’ (*note -update-at::)
-
- (-map-when 'even? 'square '(1 2 3 4))
- ⇒ '(1 4 3 16)
- (--map-when (> it 2) (* it it) '(1 2 3 4))
- ⇒ '(1 2 9 16)
- (--map-when (= it 2) 17 '(1 2 3 4))
- ⇒ '(1 17 3 4)
-
- -- Function: -map-first (pred rep list)
- Replace first item in LIST satisfying PRED with result of REP
- called on this item.
-
- See also: ‘-map-when’ (*note -map-when::), ‘-replace-first’ (*note
- -replace-first::)
-
- (-map-first 'even? 'square '(1 2 3 4))
- ⇒ '(1 4 3 4)
- (--map-first (> it 2) (* it it) '(1 2 3 4))
- ⇒ '(1 2 9 4)
- (--map-first (= it 2) 17 '(1 2 3 2))
- ⇒ '(1 17 3 2)
-
- -- Function: -map-last (pred rep list)
- Replace last item in LIST satisfying PRED with result of REP called
- on this item.
-
- See also: ‘-map-when’ (*note -map-when::), ‘-replace-last’ (*note
- -replace-last::)
-
- (-map-last 'even? 'square '(1 2 3 4))
- ⇒ '(1 2 3 16)
- (--map-last (> it 2) (* it it) '(1 2 3 4))
- ⇒ '(1 2 3 16)
- (--map-last (= it 2) 17 '(1 2 3 2))
- ⇒ '(1 2 3 17)
-
- -- Function: -map-indexed (fn list)
- Return a new list consisting of the result of (FN index item) for
- each item in LIST.
-
- In the anaphoric form ‘--map-indexed’, the index is exposed as
- symbol ‘it-index’.
-
- See also: ‘-each-indexed’ (*note -each-indexed::).
-
- (-map-indexed (lambda (index item) (- item index)) '(1 2 3 4))
- ⇒ '(1 1 1 1)
- (--map-indexed (- it it-index) '(1 2 3 4))
- ⇒ '(1 1 1 1)
-
- -- Function: -annotate (fn list)
- Return a list of cons cells where each cell is FN applied to each
- element of LIST paired with the unmodified element of LIST.
-
- (-annotate '1+ '(1 2 3))
- ⇒ '((2 . 1) (3 . 2) (4 . 3))
- (-annotate 'length '(("h" "e" "l" "l" "o") ("hello" "world")))
- ⇒ '((5 "h" "e" "l" "l" "o") (2 "hello" "world"))
- (--annotate (< 1 it) '(0 1 2 3))
- ⇒ '((nil . 0) (nil . 1) (t . 2) (t . 3))
-
- -- Function: -splice (pred fun list)
- Splice lists generated by FUN in place of elements matching PRED in
- LIST.
-
- FUN takes the element matching PRED as input.
-
- This function can be used as replacement for ‘,@’ in case you need
- to splice several lists at marked positions (for example with
- keywords).
-
- See also: ‘-splice-list’ (*note -splice-list::), ‘-insert-at’
- (*note -insert-at::)
-
- (-splice 'even? (lambda (x) (list x x)) '(1 2 3 4))
- ⇒ '(1 2 2 3 4 4)
- (--splice 't (list it it) '(1 2 3 4))
- ⇒ '(1 1 2 2 3 3 4 4)
- (--splice (equal it :magic) '((list of) (magical) (code)) '((foo) (bar) :magic (baz)))
- ⇒ '((foo) (bar) (list of) (magical) (code) (baz))
-
- -- Function: -splice-list (pred new-list list)
- Splice NEW-LIST in place of elements matching PRED in LIST.
-
- See also: ‘-splice’ (*note -splice::), ‘-insert-at’ (*note
- -insert-at::)
-
- (-splice-list 'keywordp '(a b c) '(1 :foo 2))
- ⇒ '(1 a b c 2)
- (-splice-list 'keywordp nil '(1 :foo 2))
- ⇒ '(1 2)
- (--splice-list (keywordp it) '(a b c) '(1 :foo 2))
- ⇒ '(1 a b c 2)
-
- -- Function: -mapcat (fn list)
- Return the concatenation of the result of mapping FN over LIST.
- Thus function FN should return a list.
-
- (-mapcat 'list '(1 2 3))
- ⇒ '(1 2 3)
- (-mapcat (lambda (item) (list 0 item)) '(1 2 3))
- ⇒ '(0 1 0 2 0 3)
- (--mapcat (list 0 it) '(1 2 3))
- ⇒ '(0 1 0 2 0 3)
-
- -- Function: -copy (arg)
- Create a shallow copy of LIST.
-
- (fn LIST)
-
- (-copy '(1 2 3))
- ⇒ '(1 2 3)
- (let ((a '(1 2 3))) (eq a (-copy a)))
- ⇒ nil
-
-\1f
-File: dash.info, Node: Sublist selection, Next: List to list, Prev: Maps, Up: Functions
-
-2.2 Sublist selection
-=====================
-
-Functions returning a sublist of the original list.
-
- -- Function: -filter (pred list)
- Return a new list of the items in LIST for which PRED returns a
- non-nil value.
-
- Alias: ‘-select’
-
- See also: ‘-keep’ (*note -keep::), ‘-remove’ (*note -remove::).
-
- (-filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4))
- ⇒ '(2 4)
- (-filter 'even? '(1 2 3 4))
- ⇒ '(2 4)
- (--filter (= 0 (% it 2)) '(1 2 3 4))
- ⇒ '(2 4)
-
- -- Function: -remove (pred list)
- Return a new list of the items in LIST for which PRED returns nil.
-
- Alias: ‘-reject’
-
- See also: ‘-filter’ (*note -filter::).
-
- (-remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4))
- ⇒ '(1 3)
- (-remove 'even? '(1 2 3 4))
- ⇒ '(1 3)
- (--remove (= 0 (% it 2)) '(1 2 3 4))
- ⇒ '(1 3)
-
- -- Function: -remove-first (pred list)
- Return a new list with the first item matching PRED removed.
-
- Alias: ‘-reject-first’
-
- See also: ‘-remove’ (*note -remove::), ‘-map-first’ (*note
- -map-first::)
-
- (-remove-first 'even? '(1 3 5 4 7 8 10))
- ⇒ '(1 3 5 7 8 10)
- (-remove-first 'stringp '(1 2 "first" "second" "third"))
- ⇒ '(1 2 "second" "third")
- (--remove-first (> it 3) '(1 2 3 4 5 6 7 8 9 10))
- ⇒ '(1 2 3 5 6 7 8 9 10)
-
- -- Function: -remove-last (pred list)
- Return a new list with the last item matching PRED removed.
-
- Alias: ‘-reject-last’
-
- See also: ‘-remove’ (*note -remove::), ‘-map-last’ (*note
- -map-last::)
-
- (-remove-last 'even? '(1 3 5 4 7 8 10 11))
- ⇒ '(1 3 5 4 7 8 11)
- (-remove-last 'stringp '(1 2 "last" "second" "third"))
- ⇒ '(1 2 "last" "second")
- (--remove-last (> it 3) '(1 2 3 4 5 6 7 8 9 10))
- ⇒ '(1 2 3 4 5 6 7 8 9)
-
- -- Function: -remove-item (item list)
- Remove all occurrences of ITEM from LIST.
-
- Comparison is done with ‘equal’.
-
- (-remove-item 3 '(1 2 3 2 3 4 5 3))
- ⇒ '(1 2 2 4 5)
- (-remove-item 'foo '(foo bar baz foo))
- ⇒ '(bar baz)
- (-remove-item "bob" '("alice" "bob" "eve" "bob" "dave"))
- ⇒ '("alice" "eve" "dave")
-
- -- Function: -non-nil (list)
- Return all non-nil elements of LIST.
-
- (-non-nil '(1 nil 2 nil nil 3 4 nil 5 nil))
- ⇒ '(1 2 3 4 5)
-
- -- Function: -slice (list from &optional to step)
- Return copy of LIST, starting from index FROM to index TO.
-
- FROM or TO may be negative. These values are then interpreted
- modulo the length of the list.
-
- If STEP is a number, only each STEPth item in the resulting section
- is returned. Defaults to 1.
-
- (-slice '(1 2 3 4 5) 1)
- ⇒ '(2 3 4 5)
- (-slice '(1 2 3 4 5) 0 3)
- ⇒ '(1 2 3)
- (-slice '(1 2 3 4 5 6 7 8 9) 1 -1 2)
- ⇒ '(2 4 6 8)
-
- -- Function: -take (n list)
- Return a new list of the first N items in LIST, or all items if
- there are fewer than N.
-
- See also: ‘-take-last’ (*note -take-last::)
-
- (-take 3 '(1 2 3 4 5))
- ⇒ '(1 2 3)
- (-take 17 '(1 2 3 4 5))
- ⇒ '(1 2 3 4 5)
-
- -- Function: -take-last (n list)
- Return the last N items of LIST in order.
-
- See also: ‘-take’ (*note -take::)
-
- (-take-last 3 '(1 2 3 4 5))
- ⇒ '(3 4 5)
- (-take-last 17 '(1 2 3 4 5))
- ⇒ '(1 2 3 4 5)
- (-take-last 1 '(1 2 3 4 5))
- ⇒ '(5)
-
- -- Function: -drop (n list)
- Return the tail of LIST without the first N items.
-
- See also: ‘-drop-last’ (*note -drop-last::)
-
- (fn N LIST)
-
- (-drop 3 '(1 2 3 4 5))
- ⇒ '(4 5)
- (-drop 17 '(1 2 3 4 5))
- ⇒ '()
-
- -- Function: -drop-last (n list)
- Remove the last N items of LIST and return a copy.
-
- See also: ‘-drop’ (*note -drop::)
-
- (-drop-last 3 '(1 2 3 4 5))
- ⇒ '(1 2)
- (-drop-last 17 '(1 2 3 4 5))
- ⇒ '()
-
- -- Function: -take-while (pred list)
- Return a new list of successive items from LIST while (PRED item)
- returns a non-nil value.
-
- (-take-while 'even? '(1 2 3 4))
- ⇒ '()
- (-take-while 'even? '(2 4 5 6))
- ⇒ '(2 4)
- (--take-while (< it 4) '(1 2 3 4 3 2 1))
- ⇒ '(1 2 3)
-
- -- Function: -drop-while (pred list)
- Return the tail of LIST starting from the first item for which
- (PRED item) returns nil.
-
- (-drop-while 'even? '(1 2 3 4))
- ⇒ '(1 2 3 4)
- (-drop-while 'even? '(2 4 5 6))
- ⇒ '(5 6)
- (--drop-while (< it 4) '(1 2 3 4 3 2 1))
- ⇒ '(4 3 2 1)
-
- -- Function: -select-by-indices (indices list)
- Return a list whose elements are elements from LIST selected as
- ‘(nth i list)‘ for all i from INDICES.
-
- (-select-by-indices '(4 10 2 3 6) '("v" "e" "l" "o" "c" "i" "r" "a" "p" "t" "o" "r"))
- ⇒ '("c" "o" "l" "o" "r")
- (-select-by-indices '(2 1 0) '("a" "b" "c"))
- ⇒ '("c" "b" "a")
- (-select-by-indices '(0 1 2 0 1 3 3 1) '("f" "a" "r" "l"))
- ⇒ '("f" "a" "r" "f" "a" "l" "l" "a")
-
- -- Function: -select-columns (columns table)
- Select COLUMNS from TABLE.
-
- TABLE is a list of lists where each element represents one row. It
- is assumed each row has the same length.
-
- Each row is transformed such that only the specified COLUMNS are
- selected.
-
- See also: ‘-select-column’ (*note -select-column::),
- ‘-select-by-indices’ (*note -select-by-indices::)
-
- (-select-columns '(0 2) '((1 2 3) (a b c) (:a :b :c)))
- ⇒ '((1 3) (a c) (:a :c))
- (-select-columns '(1) '((1 2 3) (a b c) (:a :b :c)))
- ⇒ '((2) (b) (:b))
- (-select-columns nil '((1 2 3) (a b c) (:a :b :c)))
- ⇒ '(nil nil nil)
-
- -- Function: -select-column (column table)
- Select COLUMN from TABLE.
-
- TABLE is a list of lists where each element represents one row. It
- is assumed each row has the same length.
-
- The single selected column is returned as a list.
-
- See also: ‘-select-columns’ (*note -select-columns::),
- ‘-select-by-indices’ (*note -select-by-indices::)
-
- (-select-column 1 '((1 2 3) (a b c) (:a :b :c)))
- ⇒ '(2 b :b)
-
-\1f
-File: dash.info, Node: List to list, Next: Reductions, Prev: Sublist selection, Up: Functions
-
-2.3 List to list
-================
-
-Functions returning a modified copy of the input list.
-
- -- Function: -keep (fn list)
- Return a new list of the non-nil results of applying FN to the
- items in LIST.
-
- If you want to select the original items satisfying a predicate use
- ‘-filter’ (*note -filter::).
-
- (-keep 'cdr '((1 2 3) (4 5) (6)))
- ⇒ '((2 3) (5))
- (-keep (lambda (num) (when (> num 3) (* 10 num))) '(1 2 3 4 5 6))
- ⇒ '(40 50 60)
- (--keep (when (> it 3) (* 10 it)) '(1 2 3 4 5 6))
- ⇒ '(40 50 60)
-
- -- Function: -concat (&rest lists)
- Return a new list with the concatenation of the elements in the
- supplied LISTS.
-
- (-concat '(1))
- ⇒ '(1)
- (-concat '(1) '(2))
- ⇒ '(1 2)
- (-concat '(1) '(2 3) '(4))
- ⇒ '(1 2 3 4)
-
- -- Function: -flatten (l)
- Take a nested list L and return its contents as a single, flat
- list.
-
- Note that because ‘nil’ represents a list of zero elements (an
- empty list), any mention of nil in L will disappear after
- flattening. If you need to preserve nils, consider ‘-flatten-n’
- (*note -flatten-n::) or map them to some unique symbol and then map
- them back.
-
- Conses of two atoms are considered "terminals", that is, they
- aren’t flattened further.
-
- See also: ‘-flatten-n’ (*note -flatten-n::)
-
- (-flatten '((1)))
- ⇒ '(1)
- (-flatten '((1 (2 3) (((4 (5)))))))
- ⇒ '(1 2 3 4 5)
- (-flatten '(1 2 (3 . 4)))
- ⇒ '(1 2 (3 . 4))
-
- -- Function: -flatten-n (num list)
- Flatten NUM levels of a nested LIST.
-
- See also: ‘-flatten’ (*note -flatten::)
-
- (-flatten-n 1 '((1 2) ((3 4) ((5 6)))))
- ⇒ '(1 2 (3 4) ((5 6)))
- (-flatten-n 2 '((1 2) ((3 4) ((5 6)))))
- ⇒ '(1 2 3 4 (5 6))
- (-flatten-n 3 '((1 2) ((3 4) ((5 6)))))
- ⇒ '(1 2 3 4 5 6)
-
- -- Function: -replace (old new list)
- Replace all OLD items in LIST with NEW.
-
- Elements are compared using ‘equal’.
-
- See also: ‘-replace-at’ (*note -replace-at::)
-
- (-replace 1 "1" '(1 2 3 4 3 2 1))
- ⇒ '("1" 2 3 4 3 2 "1")
- (-replace "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo"))
- ⇒ '("a" "nice" "bar" "sentence" "about" "bar")
- (-replace 1 2 nil)
- ⇒ nil
-
- -- Function: -replace-first (old new list)
- Replace the first occurrence of OLD with NEW in LIST.
-
- Elements are compared using ‘equal’.
-
- See also: ‘-map-first’ (*note -map-first::)
-
- (-replace-first 1 "1" '(1 2 3 4 3 2 1))
- ⇒ '("1" 2 3 4 3 2 1)
- (-replace-first "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo"))
- ⇒ '("a" "nice" "bar" "sentence" "about" "foo")
- (-replace-first 1 2 nil)
- ⇒ nil
-
- -- Function: -replace-last (old new list)
- Replace the last occurrence of OLD with NEW in LIST.
-
- Elements are compared using ‘equal’.
-
- See also: ‘-map-last’ (*note -map-last::)
-
- (-replace-last 1 "1" '(1 2 3 4 3 2 1))
- ⇒ '(1 2 3 4 3 2 "1")
- (-replace-last "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo"))
- ⇒ '("a" "nice" "foo" "sentence" "about" "bar")
- (-replace-last 1 2 nil)
- ⇒ nil
-
- -- Function: -insert-at (n x list)
- Return a list with X inserted into LIST at position N.
-
- See also: ‘-splice’ (*note -splice::), ‘-splice-list’ (*note
- -splice-list::)
-
- (-insert-at 1 'x '(a b c))
- ⇒ '(a x b c)
- (-insert-at 12 'x '(a b c))
- ⇒ '(a b c x)
-
- -- Function: -replace-at (n x list)
- Return a list with element at Nth position in LIST replaced with X.
-
- See also: ‘-replace’ (*note -replace::)
-
- (-replace-at 0 9 '(0 1 2 3 4 5))
- ⇒ '(9 1 2 3 4 5)
- (-replace-at 1 9 '(0 1 2 3 4 5))
- ⇒ '(0 9 2 3 4 5)
- (-replace-at 4 9 '(0 1 2 3 4 5))
- ⇒ '(0 1 2 3 9 5)
-
- -- Function: -update-at (n func list)
- Return a list with element at Nth position in LIST replaced with
- ‘(func (nth n list))‘.
-
- See also: ‘-map-when’ (*note -map-when::)
-
- (-update-at 0 (lambda (x) (+ x 9)) '(0 1 2 3 4 5))
- ⇒ '(9 1 2 3 4 5)
- (-update-at 1 (lambda (x) (+ x 8)) '(0 1 2 3 4 5))
- ⇒ '(0 9 2 3 4 5)
- (--update-at 2 (length it) '("foo" "bar" "baz" "quux"))
- ⇒ '("foo" "bar" 3 "quux")
-
- -- Function: -remove-at (n list)
- Return a list with element at Nth position in LIST removed.
-
- See also: ‘-remove-at-indices’ (*note -remove-at-indices::),
- ‘-remove’ (*note -remove::)
-
- (-remove-at 0 '("0" "1" "2" "3" "4" "5"))
- ⇒ '("1" "2" "3" "4" "5")
- (-remove-at 1 '("0" "1" "2" "3" "4" "5"))
- ⇒ '("0" "2" "3" "4" "5")
- (-remove-at 2 '("0" "1" "2" "3" "4" "5"))
- ⇒ '("0" "1" "3" "4" "5")
-
- -- Function: -remove-at-indices (indices list)
- Return a list whose elements are elements from LIST without
- elements selected as ‘(nth i list)‘ for all i from INDICES.
-
- See also: ‘-remove-at’ (*note -remove-at::), ‘-remove’ (*note
- -remove::)
-
- (-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5"))
- ⇒ '("1" "2" "3" "4" "5")
- (-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5"))
- ⇒ '("1" "3" "5")
- (-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5"))
- ⇒ '("1" "2" "3" "4")
-
-\1f
-File: dash.info, Node: Reductions, Next: Unfolding, Prev: List to list, Up: Functions
-
-2.4 Reductions
-==============
-
-Functions reducing lists into single value.
-
- -- Function: -reduce-from (fn initial-value list)
- Return the result of applying FN to INITIAL-VALUE and the first
- item in LIST, then applying FN to that result and the 2nd item,
- etc. If LIST contains no items, return INITIAL-VALUE and do not
- call FN.
-
- In the anaphoric form ‘--reduce-from’, the accumulated value is
- exposed as symbol ‘acc’.
-
- See also: ‘-reduce’ (*note -reduce::), ‘-reduce-r’ (*note
- -reduce-r::)
-
- (-reduce-from '- 10 '(1 2 3))
- ⇒ 4
- (-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "10" '(1 2 3))
- ⇒ "(((10 - 1) - 2) - 3)"
- (--reduce-from (concat acc " " it) "START" '("a" "b" "c"))
- ⇒ "START a b c"
-
- -- Function: -reduce-r-from (fn initial-value list)
- Replace conses with FN, nil with INITIAL-VALUE and evaluate the
- resulting expression. If LIST is empty, INITIAL-VALUE is returned
- and FN is not called.
-
- Note: this function works the same as ‘-reduce-from’ (*note
- -reduce-from::) but the operation associates from right instead of
- from left.
-
- See also: ‘-reduce-r’ (*note -reduce-r::), ‘-reduce’ (*note
- -reduce::)
-
- (-reduce-r-from '- 10 '(1 2 3))
- ⇒ -8
- (-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "10" '(1 2 3))
- ⇒ "(1 - (2 - (3 - 10)))"
- (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c"))
- ⇒ "a b c END"
-
- -- Function: -reduce (fn list)
- Return the result of applying FN to the first 2 items in LIST, then
- applying FN to that result and the 3rd item, etc. If LIST contains
- no items, return the result of calling FN with no arguments. If
- LIST contains a single item, return that item and do not call FN.
-
- In the anaphoric form ‘--reduce’, the accumulated value is exposed
- as symbol ‘acc’.
-
- See also: ‘-reduce-from’ (*note -reduce-from::), ‘-reduce-r’ (*note
- -reduce-r::)
-
- (-reduce '- '(1 2 3 4))
- ⇒ -8
- (-reduce 'list '(1 2 3 4))
- ⇒ '(((1 2) 3) 4)
- (--reduce (format "%s-%d" acc it) '(1 2 3))
- ⇒ "1-2-3"
-
- -- Function: -reduce-r (fn list)
- Replace conses with FN and evaluate the resulting expression. The
- final nil is ignored. If LIST contains no items, return the result
- of calling FN with no arguments. If LIST contains a single item,
- return that item and do not call FN.
-
- The first argument of FN is the new item, the second is the
- accumulated value.
-
- Note: this function works the same as ‘-reduce’ (*note -reduce::)
- but the operation associates from right instead of from left.
-
- See also: ‘-reduce-r-from’ (*note -reduce-r-from::), ‘-reduce’
- (*note -reduce::)
-
- (-reduce-r '- '(1 2 3 4))
- ⇒ -2
- (-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3))
- ⇒ "3-2-1"
- (--reduce-r (format "%s-%d" acc it) '(1 2 3))
- ⇒ "3-2-1"
-
- -- Function: -reductions-from (fn init list)
- Return a list of the intermediate values of the reduction.
-
- See ‘-reduce-from’ (*note -reduce-from::) for explanation of the
- arguments.
-
- See also: ‘-reductions’ (*note -reductions::), ‘-reductions-r’
- (*note -reductions-r::), ‘-reduce-r’ (*note -reduce-r::)
-
- (-reductions-from (lambda (a i) (format "(%s FN %d)" a i)) "INIT" '(1 2 3 4))
- ⇒ '("INIT" "(INIT FN 1)" "((INIT FN 1) FN 2)" "(((INIT FN 1) FN 2) FN 3)" "((((INIT FN 1) FN 2) FN 3) FN 4)")
- (-reductions-from 'max 0 '(2 1 4 3))
- ⇒ '(0 2 2 4 4)
- (-reductions-from '* 1 '(1 2 3 4))
- ⇒ '(1 1 2 6 24)
-
- -- Function: -reductions-r-from (fn init list)
- Return a list of the intermediate values of the reduction.
-
- See ‘-reduce-r-from’ (*note -reduce-r-from::) for explanation of
- the arguments.
-
- See also: ‘-reductions-r’ (*note -reductions-r::), ‘-reductions’
- (*note -reductions::), ‘-reduce’ (*note -reduce::)
-
- (-reductions-r-from (lambda (i a) (format "(%d FN %s)" i a)) "INIT" '(1 2 3 4))
- ⇒ '("(1 FN (2 FN (3 FN (4 FN INIT))))" "(2 FN (3 FN (4 FN INIT)))" "(3 FN (4 FN INIT))" "(4 FN INIT)" "INIT")
- (-reductions-r-from 'max 0 '(2 1 4 3))
- ⇒ '(4 4 4 3 0)
- (-reductions-r-from '* 1 '(1 2 3 4))
- ⇒ '(24 24 12 4 1)
-
- -- Function: -reductions (fn list)
- Return a list of the intermediate values of the reduction.
-
- See ‘-reduce’ (*note -reduce::) for explanation of the arguments.
-
- See also: ‘-reductions-from’ (*note -reductions-from::),
- ‘-reductions-r’ (*note -reductions-r::), ‘-reduce-r’ (*note
- -reduce-r::)
-
- (-reductions (lambda (a i) (format "(%s FN %d)" a i)) '(1 2 3 4))
- ⇒ '(1 "(1 FN 2)" "((1 FN 2) FN 3)" "(((1 FN 2) FN 3) FN 4)")
- (-reductions '+ '(1 2 3 4))
- ⇒ '(1 3 6 10)
- (-reductions '* '(1 2 3 4))
- ⇒ '(1 2 6 24)
-
- -- Function: -reductions-r (fn list)
- Return a list of the intermediate values of the reduction.
-
- See ‘-reduce-r’ (*note -reduce-r::) for explanation of the
- arguments.
-
- See also: ‘-reductions-r-from’ (*note -reductions-r-from::),
- ‘-reductions’ (*note -reductions::), ‘-reduce’ (*note -reduce::)
-
- (-reductions-r (lambda (i a) (format "(%d FN %s)" i a)) '(1 2 3 4))
- ⇒ '("(1 FN (2 FN (3 FN 4)))" "(2 FN (3 FN 4))" "(3 FN 4)" 4)
- (-reductions-r '+ '(1 2 3 4))
- ⇒ '(10 9 7 4)
- (-reductions-r '* '(1 2 3 4))
- ⇒ '(24 24 12 4)
-
- -- Function: -count (pred list)
- Counts the number of items in LIST where (PRED item) is non-nil.
-
- (-count 'even? '(1 2 3 4 5))
- ⇒ 2
- (--count (< it 4) '(1 2 3 4))
- ⇒ 3
-
- -- Function: -sum (list)
- Return the sum of LIST.
-
- (-sum '())
- ⇒ 0
- (-sum '(1))
- ⇒ 1
- (-sum '(1 2 3 4))
- ⇒ 10
-
- -- Function: -running-sum (list)
- Return a list with running sums of items in LIST.
-
- LIST must be non-empty.
-
- (-running-sum '(1 2 3 4))
- ⇒ '(1 3 6 10)
- (-running-sum '(1))
- ⇒ '(1)
- (-running-sum '())
- ⇒ error
-
- -- Function: -product (list)
- Return the product of LIST.
-
- (-product '())
- ⇒ 1
- (-product '(1))
- ⇒ 1
- (-product '(1 2 3 4))
- ⇒ 24
-
- -- Function: -running-product (list)
- Return a list with running products of items in LIST.
-
- LIST must be non-empty.
-
- (-running-product '(1 2 3 4))
- ⇒ '(1 2 6 24)
- (-running-product '(1))
- ⇒ '(1)
- (-running-product '())
- ⇒ error
-
- -- Function: -inits (list)
- Return all prefixes of LIST.
-
- (-inits '(1 2 3 4))
- ⇒ '(nil (1) (1 2) (1 2 3) (1 2 3 4))
- (-inits nil)
- ⇒ '(nil)
- (-inits '(1))
- ⇒ '(nil (1))
-
- -- Function: -tails (list)
- Return all suffixes of LIST
-
- (-tails '(1 2 3 4))
- ⇒ '((1 2 3 4) (2 3 4) (3 4) (4) nil)
- (-tails nil)
- ⇒ '(nil)
- (-tails '(1))
- ⇒ '((1) nil)
-
- -- Function: -common-prefix (&rest lists)
- Return the longest common prefix of LISTS.
-
- (-common-prefix '(1))
- ⇒ '(1)
- (-common-prefix '(1 2) '(3 4) '(1 2))
- ⇒ nil
- (-common-prefix '(1 2) '(1 2 3) '(1 2 3 4))
- ⇒ '(1 2)
-
- -- Function: -common-suffix (&rest lists)
- Return the longest common suffix of LISTS.
-
- (-common-suffix '(1))
- ⇒ '(1)
- (-common-suffix '(1 2) '(3 4) '(1 2))
- ⇒ nil
- (-common-suffix '(1 2 3 4) '(2 3 4) '(3 4))
- ⇒ '(3 4)
-
- -- Function: -min (list)
- Return the smallest value from LIST of numbers or markers.
-
- (-min '(0))
- ⇒ 0
- (-min '(3 2 1))
- ⇒ 1
- (-min '(1 2 3))
- ⇒ 1
-
- -- Function: -min-by (comparator list)
- Take a comparison function COMPARATOR and a LIST and return the
- least element of the list by the comparison function.
-
- See also combinator ‘-on’ (*note -on::) which can transform the
- values before comparing them.
-
- (-min-by '> '(4 3 6 1))
- ⇒ 1
- (--min-by (> (car it) (car other)) '((1 2 3) (2) (3 2)))
- ⇒ '(1 2 3)
- (--min-by (> (length it) (length other)) '((1 2 3) (2) (3 2)))
- ⇒ '(2)
-
- -- Function: -max (list)
- Return the largest value from LIST of numbers or markers.
-
- (-max '(0))
- ⇒ 0
- (-max '(3 2 1))
- ⇒ 3
- (-max '(1 2 3))
- ⇒ 3
-
- -- Function: -max-by (comparator list)
- Take a comparison function COMPARATOR and a LIST and return the
- greatest element of the list by the comparison function.
-
- See also combinator ‘-on’ (*note -on::) which can transform the
- values before comparing them.
-
- (-max-by '> '(4 3 6 1))
- ⇒ 6
- (--max-by (> (car it) (car other)) '((1 2 3) (2) (3 2)))
- ⇒ '(3 2)
- (--max-by (> (length it) (length other)) '((1 2 3) (2) (3 2)))
- ⇒ '(1 2 3)
-
-\1f
-File: dash.info, Node: Unfolding, Next: Predicates, Prev: Reductions, Up: Functions
-
-2.5 Unfolding
-=============
-
-Operations dual to reductions, building lists from seed value rather
-than consuming a list to produce a single value.
-
- -- Function: -iterate (fun init n)
- Return a list of iterated applications of FUN to INIT.
-
- This means a list of form:
-
- (init (fun init) (fun (fun init)) ...)
-
- N is the length of the returned list.
-
- (-iterate '1+ 1 10)
- ⇒ '(1 2 3 4 5 6 7 8 9 10)
- (-iterate (lambda (x) (+ x x)) 2 5)
- ⇒ '(2 4 8 16 32)
- (--iterate (* it it) 2 5)
- ⇒ '(2 4 16 256 65536)
-
- -- Function: -unfold (fun seed)
- Build a list from SEED using FUN.
-
- This is "dual" operation to ‘-reduce-r’ (*note -reduce-r::): while
- -reduce-r consumes a list to produce a single value, ‘-unfold’
- (*note -unfold::) takes a seed value and builds a (potentially
- infinite!) list.
-
- FUN should return ‘nil’ to stop the generating process, or a cons
- (A . B), where A will be prepended to the result and B is the new
- seed.
-
- (-unfold (lambda (x) (unless (= x 0) (cons x (1- x)))) 10)
- ⇒ '(10 9 8 7 6 5 4 3 2 1)
- (--unfold (when it (cons it (cdr it))) '(1 2 3 4))
- ⇒ '((1 2 3 4) (2 3 4) (3 4) (4))
- (--unfold (when it (cons it (butlast it))) '(1 2 3 4))
- ⇒ '((1 2 3 4) (1 2 3) (1 2) (1))
-
-\1f
-File: dash.info, Node: Predicates, Next: Partitioning, Prev: Unfolding, Up: Functions
-
-2.6 Predicates
-==============
-
- -- Function: -any? (pred list)
- Return t if (PRED x) is non-nil for any x in LIST, else nil.
-
- Alias: ‘-any-p’, ‘-some?’, ‘-some-p’
-
- (-any? 'even? '(1 2 3))
- ⇒ t
- (-any? 'even? '(1 3 5))
- ⇒ nil
- (-any? 'null '(1 3 5))
- ⇒ nil
-
- -- Function: -all? (pred list)
- Return t if (PRED x) is non-nil for all x in LIST, else nil.
-
- Alias: ‘-all-p’, ‘-every?’, ‘-every-p’
-
- (-all? 'even? '(1 2 3))
- ⇒ nil
- (-all? 'even? '(2 4 6))
- ⇒ t
- (--all? (= 0 (% it 2)) '(2 4 6))
- ⇒ t
-
- -- Function: -none? (pred list)
- Return t if (PRED x) is nil for all x in LIST, else nil.
-
- Alias: ‘-none-p’
-
- (-none? 'even? '(1 2 3))
- ⇒ nil
- (-none? 'even? '(1 3 5))
- ⇒ t
- (--none? (= 0 (% it 2)) '(1 2 3))
- ⇒ nil
-
- -- Function: -only-some? (pred list)
- Return ‘t‘ if at least one item of LIST matches PRED and at least
- one item of LIST does not match PRED. Return ‘nil‘ both if all
- items match the predicate or if none of the items match the
- predicate.
-
- Alias: ‘-only-some-p’
-
- (-only-some? 'even? '(1 2 3))
- ⇒ t
- (-only-some? 'even? '(1 3 5))
- ⇒ nil
- (-only-some? 'even? '(2 4 6))
- ⇒ nil
-
- -- Function: -contains? (list element)
- Return non-nil if LIST contains ELEMENT.
-
- The test for equality is done with ‘equal’, or with ‘-compare-fn’
- if that’s non-nil.
-
- Alias: ‘-contains-p’
-
- (-contains? '(1 2 3) 1)
- ⇒ t
- (-contains? '(1 2 3) 2)
- ⇒ t
- (-contains? '(1 2 3) 4)
- ⇒ nil
-
- -- Function: -same-items? (list list2)
- Return true if LIST and LIST2 has the same items.
-
- The order of the elements in the lists does not matter.
-
- Alias: ‘-same-items-p’
-
- (-same-items? '(1 2 3) '(1 2 3))
- ⇒ t
- (-same-items? '(1 2 3) '(3 2 1))
- ⇒ t
- (-same-items? '(1 2 3) '(1 2 3 4))
- ⇒ nil
-
- -- Function: -is-prefix? (prefix list)
- Return non-nil if PREFIX is prefix of LIST.
-
- Alias: ‘-is-prefix-p’
-
- (-is-prefix? '(1 2 3) '(1 2 3 4 5))
- ⇒ t
- (-is-prefix? '(1 2 3 4 5) '(1 2 3))
- ⇒ nil
- (-is-prefix? '(1 3) '(1 2 3 4 5))
- ⇒ nil
-
- -- Function: -is-suffix? (suffix list)
- Return non-nil if SUFFIX is suffix of LIST.
-
- Alias: ‘-is-suffix-p’
-
- (-is-suffix? '(3 4 5) '(1 2 3 4 5))
- ⇒ t
- (-is-suffix? '(1 2 3 4 5) '(3 4 5))
- ⇒ nil
- (-is-suffix? '(3 5) '(1 2 3 4 5))
- ⇒ nil
-
- -- Function: -is-infix? (infix list)
- Return non-nil if INFIX is infix of LIST.
-
- This operation runs in O(n^2) time
-
- Alias: ‘-is-infix-p’
-
- (-is-infix? '(1 2 3) '(1 2 3 4 5))
- ⇒ t
- (-is-infix? '(2 3 4) '(1 2 3 4 5))
- ⇒ t
- (-is-infix? '(3 4 5) '(1 2 3 4 5))
- ⇒ t
-
-\1f
-File: dash.info, Node: Partitioning, Next: Indexing, Prev: Predicates, Up: Functions
-
-2.7 Partitioning
-================
-
-Functions partitioning the input list into a list of lists.
-
- -- Function: -split-at (n list)
- Return a list of ((-take N LIST) (-drop N LIST)), in no more than
- one pass through the list.
-
- (-split-at 3 '(1 2 3 4 5))
- ⇒ '((1 2 3) (4 5))
- (-split-at 17 '(1 2 3 4 5))
- ⇒ '((1 2 3 4 5) nil)
-
- -- Function: -split-with (pred list)
- Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)),
- in no more than one pass through the list.
-
- (-split-with 'even? '(1 2 3 4))
- ⇒ '(nil (1 2 3 4))
- (-split-with 'even? '(2 4 5 6))
- ⇒ '((2 4) (5 6))
- (--split-with (< it 4) '(1 2 3 4 3 2 1))
- ⇒ '((1 2 3) (4 3 2 1))
-
- -- Macro: -split-on (item list)
- Split the LIST each time ITEM is found.
-
- Unlike ‘-partition-by’ (*note -partition-by::), the ITEM is
- discarded from the results. Empty lists are also removed from the
- result.
-
- Comparison is done by ‘equal’.
-
- See also ‘-split-when’ (*note -split-when::)
-
- (-split-on '| '(Nil | Leaf a | Node [Tree a]))
- ⇒ '((Nil) (Leaf a) (Node [Tree a]))
- (-split-on ':endgroup '("a" "b" :endgroup "c" :endgroup "d" "e"))
- ⇒ '(("a" "b") ("c") ("d" "e"))
- (-split-on ':endgroup '("a" "b" :endgroup :endgroup "d" "e"))
- ⇒ '(("a" "b") ("d" "e"))
-
- -- Function: -split-when (fn list)
- Split the LIST on each element where FN returns non-nil.
-
- Unlike ‘-partition-by’ (*note -partition-by::), the "matched"
- element is discarded from the results. Empty lists are also
- removed from the result.
-
- This function can be thought of as a generalization of
- ‘split-string’.
-
- (-split-when 'even? '(1 2 3 4 5 6))
- ⇒ '((1) (3) (5))
- (-split-when 'even? '(1 2 3 4 6 8 9))
- ⇒ '((1) (3) (9))
- (--split-when (memq it '(&optional &rest)) '(a b &optional c d &rest args))
- ⇒ '((a b) (c d) (args))
-
- -- Function: -separate (pred list)
- Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one
- pass through the list.
-
- (-separate (lambda (num) (= 0 (% num 2))) '(1 2 3 4 5 6 7))
- ⇒ '((2 4 6) (1 3 5 7))
- (--separate (< it 5) '(3 7 5 9 3 2 1 4 6))
- ⇒ '((3 3 2 1 4) (7 5 9 6))
- (-separate 'cdr '((1 2) (1) (1 2 3) (4)))
- ⇒ '(((1 2) (1 2 3)) ((1) (4)))
-
- -- Function: -partition (n list)
- Return a new list with the items in LIST grouped into N-sized
- sublists. If there are not enough items to make the last group
- N-sized, those items are discarded.
-
- (-partition 2 '(1 2 3 4 5 6))
- ⇒ '((1 2) (3 4) (5 6))
- (-partition 2 '(1 2 3 4 5 6 7))
- ⇒ '((1 2) (3 4) (5 6))
- (-partition 3 '(1 2 3 4 5 6 7))
- ⇒ '((1 2 3) (4 5 6))
-
- -- Function: -partition-all (n list)
- Return a new list with the items in LIST grouped into N-sized
- sublists. The last group may contain less than N items.
-
- (-partition-all 2 '(1 2 3 4 5 6))
- ⇒ '((1 2) (3 4) (5 6))
- (-partition-all 2 '(1 2 3 4 5 6 7))
- ⇒ '((1 2) (3 4) (5 6) (7))
- (-partition-all 3 '(1 2 3 4 5 6 7))
- ⇒ '((1 2 3) (4 5 6) (7))
-
- -- Function: -partition-in-steps (n step list)
- Return a new list with the items in LIST grouped into N-sized
- sublists at offsets STEP apart. If there are not enough items to
- make the last group N-sized, those items are discarded.
-
- (-partition-in-steps 2 1 '(1 2 3 4))
- ⇒ '((1 2) (2 3) (3 4))
- (-partition-in-steps 3 2 '(1 2 3 4))
- ⇒ '((1 2 3))
- (-partition-in-steps 3 2 '(1 2 3 4 5))
- ⇒ '((1 2 3) (3 4 5))
-
- -- Function: -partition-all-in-steps (n step list)
- Return a new list with the items in LIST grouped into N-sized
- sublists at offsets STEP apart. The last groups may contain less
- than N items.
-
- (-partition-all-in-steps 2 1 '(1 2 3 4))
- ⇒ '((1 2) (2 3) (3 4) (4))
- (-partition-all-in-steps 3 2 '(1 2 3 4))
- ⇒ '((1 2 3) (3 4))
- (-partition-all-in-steps 3 2 '(1 2 3 4 5))
- ⇒ '((1 2 3) (3 4 5) (5))
-
- -- Function: -partition-by (fn list)
- Apply FN to each item in LIST, splitting it each time FN returns a
- new value.
-
- (-partition-by 'even? '())
- ⇒ '()
- (-partition-by 'even? '(1 1 2 2 2 3 4 6 8))
- ⇒ '((1 1) (2 2 2) (3) (4 6 8))
- (--partition-by (< it 3) '(1 2 3 4 3 2 1))
- ⇒ '((1 2) (3 4 3) (2 1))
-
- -- Function: -partition-by-header (fn list)
- Apply FN to the first item in LIST. That is the header value.
- Apply FN to each item in LIST, splitting it each time FN returns
- the header value, but only after seeing at least one other value
- (the body).
-
- (--partition-by-header (= it 1) '(1 2 3 1 2 1 2 3 4))
- ⇒ '((1 2 3) (1 2) (1 2 3 4))
- (--partition-by-header (> it 0) '(1 2 0 1 0 1 2 3 0))
- ⇒ '((1 2 0) (1 0) (1 2 3 0))
- (-partition-by-header 'even? '(2 1 1 1 4 1 3 5 6 6 1))
- ⇒ '((2 1 1 1) (4 1 3 5) (6 6 1))
-
- -- Function: -partition-after-pred (pred list)
- Partition directly after each time PRED is true on an element of
- LIST.
-
- (-partition-after-pred #'odd? '())
- ⇒ '()
- (-partition-after-pred #'odd? '(1))
- ⇒ '((1))
- (-partition-after-pred #'odd? '(0 1))
- ⇒ '((0 1))
-
- -- Function: -partition-before-pred (pred list)
- Partition directly before each time PRED is true on an element of
- LIST.
-
- (-partition-before-pred #'odd? '())
- ⇒ '()
- (-partition-before-pred #'odd? '(1))
- ⇒ '((1))
- (-partition-before-pred #'odd? '(0 1))
- ⇒ '((0) (1))
-
- -- Function: -partition-before-item (item list)
- Partition directly before each time ITEM appears in LIST.
-
- (-partition-before-item 3 '())
- ⇒ '()
- (-partition-before-item 3 '(1))
- ⇒ '((1))
- (-partition-before-item 3 '(3))
- ⇒ '((3))
-
- -- Function: -partition-after-item (item list)
- Partition directly after each time ITEM appears in LIST.
-
- (-partition-after-item 3 '())
- ⇒ '()
- (-partition-after-item 3 '(1))
- ⇒ '((1))
- (-partition-after-item 3 '(3))
- ⇒ '((3))
-
- -- Function: -group-by (fn list)
- Separate LIST into an alist whose keys are FN applied to the
- elements of LIST. Keys are compared by ‘equal’.
-
- (-group-by 'even? '())
- ⇒ '()
- (-group-by 'even? '(1 1 2 2 2 3 4 6 8))
- ⇒ '((nil 1 1 3) (t 2 2 2 4 6 8))
- (--group-by (car (split-string it "/")) '("a/b" "c/d" "a/e"))
- ⇒ '(("a" "a/b" "a/e") ("c" "c/d"))
-
-\1f
-File: dash.info, Node: Indexing, Next: Set operations, Prev: Partitioning, Up: Functions
-
-2.8 Indexing
-============
-
-Return indices of elements based on predicates, sort elements by indices
-etc.
-
- -- Function: -elem-index (elem list)
- Return the index of the first element in the given LIST which is
- equal to the query element ELEM, or nil if there is no such
- element.
-
- (-elem-index 2 '(6 7 8 2 3 4))
- ⇒ 3
- (-elem-index "bar" '("foo" "bar" "baz"))
- ⇒ 1
- (-elem-index '(1 2) '((3) (5 6) (1 2) nil))
- ⇒ 2
-
- -- Function: -elem-indices (elem list)
- Return the indices of all elements in LIST equal to the query
- element ELEM, in ascending order.
-
- (-elem-indices 2 '(6 7 8 2 3 4 2 1))
- ⇒ '(3 6)
- (-elem-indices "bar" '("foo" "bar" "baz"))
- ⇒ '(1)
- (-elem-indices '(1 2) '((3) (1 2) (5 6) (1 2) nil))
- ⇒ '(1 3)
-
- -- Function: -find-index (pred list)
- Take a predicate PRED and a LIST and return the index of the first
- element in the list satisfying the predicate, or nil if there is no
- such element.
-
- See also ‘-first’ (*note -first::).
-
- (-find-index 'even? '(2 4 1 6 3 3 5 8))
- ⇒ 0
- (--find-index (< 5 it) '(2 4 1 6 3 3 5 8))
- ⇒ 3
- (-find-index (-partial 'string-lessp "baz") '("bar" "foo" "baz"))
- ⇒ 1
-
- -- Function: -find-last-index (pred list)
- Take a predicate PRED and a LIST and return the index of the last
- element in the list satisfying the predicate, or nil if there is no
- such element.
-
- See also ‘-last’ (*note -last::).
-
- (-find-last-index 'even? '(2 4 1 6 3 3 5 8))
- ⇒ 7
- (--find-last-index (< 5 it) '(2 7 1 6 3 8 5 2))
- ⇒ 5
- (-find-last-index (-partial 'string-lessp "baz") '("q" "foo" "baz"))
- ⇒ 1
-
- -- Function: -find-indices (pred list)
- Return the indices of all elements in LIST satisfying the predicate
- PRED, in ascending order.
-
- (-find-indices 'even? '(2 4 1 6 3 3 5 8))
- ⇒ '(0 1 3 7)
- (--find-indices (< 5 it) '(2 4 1 6 3 3 5 8))
- ⇒ '(3 7)
- (-find-indices (-partial 'string-lessp "baz") '("bar" "foo" "baz"))
- ⇒ '(1)
-
- -- Function: -grade-up (comparator list)
- Grade elements of LIST using COMPARATOR relation, yielding a
- permutation vector such that applying this permutation to LIST
- sorts it in ascending order.
-
- (-grade-up '< '(3 1 4 2 1 3 3))
- ⇒ '(1 4 3 0 5 6 2)
- (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-up '< l) l))
- ⇒ '(1 1 2 3 3 3 4)
-
- -- Function: -grade-down (comparator list)
- Grade elements of LIST using COMPARATOR relation, yielding a
- permutation vector such that applying this permutation to LIST
- sorts it in descending order.
-
- (-grade-down '< '(3 1 4 2 1 3 3))
- ⇒ '(2 0 5 6 3 1 4)
- (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-down '< l) l))
- ⇒ '(4 3 3 3 2 1 1)
-
-\1f
-File: dash.info, Node: Set operations, Next: Other list operations, Prev: Indexing, Up: Functions
-
-2.9 Set operations
-==================
-
-Operations pretending lists are sets.
-
- -- Function: -union (list list2)
- Return a new list containing the elements of LIST and elements of
- LIST2 that are not in LIST. The test for equality is done with
- ‘equal’, or with ‘-compare-fn’ if that’s non-nil.
-
- (-union '(1 2 3) '(3 4 5))
- ⇒ '(1 2 3 4 5)
- (-union '(1 2 3 4) '())
- ⇒ '(1 2 3 4)
- (-union '(1 1 2 2) '(3 2 1))
- ⇒ '(1 1 2 2 3)
-
- -- Function: -difference (list list2)
- Return a new list with only the members of LIST that are not in
- LIST2. The test for equality is done with ‘equal’, or with
- ‘-compare-fn’ if that’s non-nil.
-
- (-difference '() '())
- ⇒ '()
- (-difference '(1 2 3) '(4 5 6))
- ⇒ '(1 2 3)
- (-difference '(1 2 3 4) '(3 4 5 6))
- ⇒ '(1 2)
-
- -- Function: -intersection (list list2)
- Return a new list containing only the elements that are members of
- both LIST and LIST2. The test for equality is done with ‘equal’,
- or with ‘-compare-fn’ if that’s non-nil.
-
- (-intersection '() '())
- ⇒ '()
- (-intersection '(1 2 3) '(4 5 6))
- ⇒ '()
- (-intersection '(1 2 3 4) '(3 4 5 6))
- ⇒ '(3 4)
-
- -- Function: -powerset (list)
- Return the power set of LIST.
-
- (-powerset '())
- ⇒ '(nil)
- (-powerset '(x y z))
- ⇒ '((x y z) (x y) (x z) (x) (y z) (y) (z) nil)
-
- -- Function: -permutations (list)
- Return the permutations of LIST.
-
- (-permutations '())
- ⇒ '(nil)
- (-permutations '(1 2))
- ⇒ '((1 2) (2 1))
- (-permutations '(a b c))
- ⇒ '((a b c) (a c b) (b a c) (b c a) (c a b) (c b a))
-
- -- Function: -distinct (list)
- Return a new list with all duplicates removed. The test for
- equality is done with ‘equal’, or with ‘-compare-fn’ if that’s
- non-nil.
-
- Alias: ‘-uniq’
-
- (-distinct '())
- ⇒ '()
- (-distinct '(1 2 2 4))
- ⇒ '(1 2 4)
- (-distinct '(t t t))
- ⇒ '(t)
-
-\1f
-File: dash.info, Node: Other list operations, Next: Tree operations, Prev: Set operations, Up: Functions
-
-2.10 Other list operations
-==========================
-
-Other list functions not fit to be classified elsewhere.
-
- -- Function: -rotate (n list)
- Rotate LIST N places to the right. With N negative, rotate to the
- left. The time complexity is O(n).
-
- (-rotate 3 '(1 2 3 4 5 6 7))
- ⇒ '(5 6 7 1 2 3 4)
- (-rotate -3 '(1 2 3 4 5 6 7))
- ⇒ '(4 5 6 7 1 2 3)
- (-rotate 16 '(1 2 3 4 5 6 7))
- ⇒ '(6 7 1 2 3 4 5)
-
- -- Function: -repeat (n x)
- Return a list with X repeated N times. Return nil if N is less
- than 1.
-
- (-repeat 3 :a)
- ⇒ '(:a :a :a)
- (-repeat 1 :a)
- ⇒ '(:a)
- (-repeat 0 :a)
- ⇒ nil
-
- -- Function: -cons* (&rest args)
- Make a new list from the elements of ARGS.
-
- The last 2 members of ARGS are used as the final cons of the result
- so if the final member of ARGS is not a list the result is a dotted
- list.
-
- (-cons* 1 2)
- ⇒ '(1 . 2)
- (-cons* 1 2 3)
- ⇒ '(1 2 . 3)
- (-cons* 1)
- ⇒ 1
-
- -- Function: -snoc (list elem &rest elements)
- Append ELEM to the end of the list.
-
- This is like ‘cons’, but operates on the end of list.
-
- If ELEMENTS is non nil, append these to the list as well.
-
- (-snoc '(1 2 3) 4)
- ⇒ '(1 2 3 4)
- (-snoc '(1 2 3) 4 5 6)
- ⇒ '(1 2 3 4 5 6)
- (-snoc '(1 2 3) '(4 5 6))
- ⇒ '(1 2 3 (4 5 6))
-
- -- Function: -interpose (sep list)
- Return a new list of all elements in LIST separated by SEP.
-
- (-interpose "-" '())
- ⇒ '()
- (-interpose "-" '("a"))
- ⇒ '("a")
- (-interpose "-" '("a" "b" "c"))
- ⇒ '("a" "-" "b" "-" "c")
-
- -- Function: -interleave (&rest lists)
- Return a new list of the first item in each list, then the second
- etc.
-
- (-interleave '(1 2) '("a" "b"))
- ⇒ '(1 "a" 2 "b")
- (-interleave '(1 2) '("a" "b") '("A" "B"))
- ⇒ '(1 "a" "A" 2 "b" "B")
- (-interleave '(1 2 3) '("a" "b"))
- ⇒ '(1 "a" 2 "b")
-
- -- Function: -zip-with (fn list1 list2)
- Zip the two lists LIST1 and LIST2 using a function FN. This
- function is applied pairwise taking as first argument element of
- LIST1 and as second argument element of LIST2 at corresponding
- position.
-
- The anaphoric form ‘--zip-with’ binds the elements from LIST1 as
- symbol ‘it’, and the elements from LIST2 as symbol ‘other’.
-
- (-zip-with '+ '(1 2 3) '(4 5 6))
- ⇒ '(5 7 9)
- (-zip-with 'cons '(1 2 3) '(4 5 6))
- ⇒ '((1 . 4) (2 . 5) (3 . 6))
- (--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde"))
- ⇒ '("Batman and Robin" "Jekyll and Hyde")
-
- -- Function: -zip (&rest lists)
- Zip LISTS together. Group the head of each list, followed by the
- second elements of each list, and so on. The lengths of the
- returned groupings are equal to the length of the shortest input
- list.
-
- If two lists are provided as arguments, return the groupings as a
- list of cons cells. Otherwise, return the groupings as a list of
- lists.
-
- Use ‘-zip-lists’ (*note -zip-lists::) if you need the return value
- to always be a list of lists.
-
- Alias: ‘-zip-pair’
-
- See also: ‘-zip-lists’ (*note -zip-lists::)
-
- (-zip '(1 2 3) '(4 5 6))
- ⇒ '((1 . 4) (2 . 5) (3 . 6))
- (-zip '(1 2 3) '(4 5 6 7))
- ⇒ '((1 . 4) (2 . 5) (3 . 6))
- (-zip '(1 2) '(3 4 5) '(6))
- ⇒ '((1 3 6))
-
- -- Function: -zip-lists (&rest lists)
- Zip LISTS together. Group the head of each list, followed by the
- second elements of each list, and so on. The lengths of the
- returned groupings are equal to the length of the shortest input
- list.
-
- The return value is always list of lists, which is a difference
- from ‘-zip-pair’ which returns a cons-cell in case two input lists
- are provided.
-
- See also: ‘-zip’ (*note -zip::)
-
- (-zip-lists '(1 2 3) '(4 5 6))
- ⇒ '((1 4) (2 5) (3 6))
- (-zip-lists '(1 2 3) '(4 5 6 7))
- ⇒ '((1 4) (2 5) (3 6))
- (-zip-lists '(1 2) '(3 4 5) '(6))
- ⇒ '((1 3 6))
-
- -- Function: -zip-fill (fill-value &rest lists)
- Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
- lengths of the returned groupings are equal to the length of the
- longest input list.
-
- (-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9))
- ⇒ '((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0))
-
- -- Function: -unzip (lists)
- Unzip LISTS.
-
- This works just like ‘-zip’ (*note -zip::) but takes a list of
- lists instead of a variable number of arguments, such that
-
- (-unzip (-zip L1 L2 L3 ...))
-
- is identity (given that the lists are the same length).
-
- Note in particular that calling this on a list of two lists will
- return a list of cons-cells such that the aboce identity works.
-
- See also: ‘-zip’ (*note -zip::)
-
- (-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g")))
- ⇒ '((1 2 3) (a b c) ("e" "f" "g"))
- (-unzip '((1 2) (3 4) (5 6) (7 8) (9 10)))
- ⇒ '((1 3 5 7 9) (2 4 6 8 10))
- (-unzip '((1 2) (3 4)))
- ⇒ '((1 . 3) (2 . 4))
-
- -- Function: -cycle (list)
- Return an infinite copy of LIST that will cycle through the
- elements and repeat from the beginning.
-
- (-take 5 (-cycle '(1 2 3)))
- ⇒ '(1 2 3 1 2)
- (-take 7 (-cycle '(1 "and" 3)))
- ⇒ '(1 "and" 3 1 "and" 3 1)
- (-zip (-cycle '(1 2 3)) '(1 2))
- ⇒ '((1 . 1) (2 . 2))
-
- -- Function: -pad (fill-value &rest lists)
- Appends FILL-VALUE to the end of each list in LISTS such that they
- will all have the same length.
-
- (-pad 0 '())
- ⇒ '(nil)
- (-pad 0 '(1))
- ⇒ '((1))
- (-pad 0 '(1 2 3) '(4 5))
- ⇒ '((1 2 3) (4 5 0))
-
- -- Function: -table (fn &rest lists)
- Compute outer product of LISTS using function FN.
-
- The function FN should have the same arity as the number of
- supplied lists.
-
- The outer product is computed by applying fn to all possible
- combinations created by taking one element from each list in order.
- The dimension of the result is (length lists).
-
- See also: ‘-table-flat’ (*note -table-flat::)
-
- (-table '* '(1 2 3) '(1 2 3))
- ⇒ '((1 2 3) (2 4 6) (3 6 9))
- (-table (lambda (a b) (-sum (-zip-with '* a b))) '((1 2) (3 4)) '((1 3) (2 4)))
- ⇒ '((7 15) (10 22))
- (apply '-table 'list (-repeat 3 '(1 2)))
- ⇒ '((((1 1 1) (2 1 1)) ((1 2 1) (2 2 1))) (((1 1 2) (2 1 2)) ((1 2 2) (2 2 2))))
-
- -- Function: -table-flat (fn &rest lists)
- Compute flat outer product of LISTS using function FN.
-
- The function FN should have the same arity as the number of
- supplied lists.
-
- The outer product is computed by applying fn to all possible
- combinations created by taking one element from each list in order.
- The results are flattened, ignoring the tensor structure of the
- result. This is equivalent to calling:
-
- (-flatten-n (1- (length lists)) (apply ’-table fn lists))
-
- but the implementation here is much more efficient.
-
- See also: ‘-flatten-n’ (*note -flatten-n::), ‘-table’ (*note
- -table::)
-
- (-table-flat 'list '(1 2 3) '(a b c))
- ⇒ '((1 a) (2 a) (3 a) (1 b) (2 b) (3 b) (1 c) (2 c) (3 c))
- (-table-flat '* '(1 2 3) '(1 2 3))
- ⇒ '(1 2 3 2 4 6 3 6 9)
- (apply '-table-flat 'list (-repeat 3 '(1 2)))
- ⇒ '((1 1 1) (2 1 1) (1 2 1) (2 2 1) (1 1 2) (2 1 2) (1 2 2) (2 2 2))
-
- -- Function: -first (pred list)
- Return the first x in LIST where (PRED x) is non-nil, else nil.
-
- To get the first item in the list no questions asked, use ‘car’.
-
- Alias: ‘-find’
-
- (-first 'even? '(1 2 3))
- ⇒ 2
- (-first 'even? '(1 3 5))
- ⇒ nil
- (-first 'null '(1 3 5))
- ⇒ nil
-
- -- Function: -some (pred list)
- Return (PRED x) for the first LIST item where (PRED x) is non-nil,
- else nil.
-
- Alias: ‘-any’
-
- (-some 'even? '(1 2 3))
- ⇒ t
- (-some 'null '(1 2 3))
- ⇒ nil
- (-some 'null '(1 2 nil))
- ⇒ t
-
- -- Function: -last (pred list)
- Return the last x in LIST where (PRED x) is non-nil, else nil.
-
- (-last 'even? '(1 2 3 4 5 6 3 3 3))
- ⇒ 6
- (-last 'even? '(1 3 7 5 9))
- ⇒ nil
- (--last (> (length it) 3) '("a" "looong" "word" "and" "short" "one"))
- ⇒ "short"
-
- -- Function: -first-item (list)
- Return the first item of LIST, or nil on an empty list.
-
- See also: ‘-second-item’ (*note -second-item::), ‘-last-item’
- (*note -last-item::).
-
- (fn LIST)
-
- (-first-item '(1 2 3))
- ⇒ 1
- (-first-item nil)
- ⇒ nil
- (let ((list (list 1 2 3))) (setf (-first-item list) 5) list)
- ⇒ '(5 2 3)
-
- -- Function: -second-item (arg1)
- Return the second item of LIST, or nil if LIST is too short.
-
- See also: ‘-third-item’ (*note -third-item::).
-
- (fn LIST)
-
- (-second-item '(1 2 3))
- ⇒ 2
- (-second-item nil)
- ⇒ nil
-
- -- Function: -third-item (arg1)
- Return the third item of LIST, or nil if LIST is too short.
-
- See also: ‘-fourth-item’ (*note -fourth-item::).
-
- (fn LIST)
-
- (-third-item '(1 2 3))
- ⇒ 3
- (-third-item nil)
- ⇒ nil
-
- -- Function: -fourth-item (list)
- Return the fourth item of LIST, or nil if LIST is too short.
-
- See also: ‘-fifth-item’ (*note -fifth-item::).
-
- (-fourth-item '(1 2 3 4))
- ⇒ 4
- (-fourth-item nil)
- ⇒ nil
-
- -- Function: -fifth-item (list)
- Return the fifth item of LIST, or nil if LIST is too short.
-
- See also: ‘-last-item’ (*note -last-item::).
-
- (-fifth-item '(1 2 3 4 5))
- ⇒ 5
- (-fifth-item nil)
- ⇒ nil
-
- -- Function: -last-item (list)
- Return the last item of LIST, or nil on an empty list.
-
- (-last-item '(1 2 3))
- ⇒ 3
- (-last-item nil)
- ⇒ nil
- (let ((list (list 1 2 3))) (setf (-last-item list) 5) list)
- ⇒ '(1 2 5)
-
- -- Function: -butlast (list)
- Return a list of all items in list except for the last.
-
- (-butlast '(1 2 3))
- ⇒ '(1 2)
- (-butlast '(1 2))
- ⇒ '(1)
- (-butlast '(1))
- ⇒ nil
-
- -- Function: -sort (comparator list)
- Sort LIST, stably, comparing elements using COMPARATOR. Return the
- sorted list. LIST is NOT modified by side effects. COMPARATOR is
- called with two elements of LIST, and should return non-nil if the
- first element should sort before the second.
-
- (-sort '< '(3 1 2))
- ⇒ '(1 2 3)
- (-sort '> '(3 1 2))
- ⇒ '(3 2 1)
- (--sort (< it other) '(3 1 2))
- ⇒ '(1 2 3)
-
- -- Function: -list (&rest args)
- Return a list with ARGS.
-
- If first item of ARGS is already a list, simply return ARGS. If
- not, return a list with ARGS as elements.
-
- (-list 1)
- ⇒ '(1)
- (-list 1 2 3)
- ⇒ '(1 2 3)
- (-list '(1 2 3))
- ⇒ '(1 2 3)
-
- -- Function: -fix (fn list)
- Compute the (least) fixpoint of FN with initial input LIST.
-
- FN is called at least once, results are compared with ‘equal’.
-
- (-fix (lambda (l) (-non-nil (--mapcat (-split-at (/ (length it) 2) it) l))) '((1 2 3 4 5 6)))
- ⇒ '((1) (2) (3) (4) (5) (6))
- (let ((data '(("starwars" "scifi") ("jedi" "starwars" "warrior")))) (--fix (-uniq (--mapcat (cons it (cdr (assoc it data))) it)) '("jedi" "book")))
- ⇒ '("jedi" "starwars" "warrior" "scifi" "book")
-
-\1f
-File: dash.info, Node: Tree operations, Next: Threading macros, Prev: Other list operations, Up: Functions
-
-2.11 Tree operations
-====================
-
-Functions pretending lists are trees.
-
- -- Function: -tree-seq (branch children tree)
- Return a sequence of the nodes in TREE, in depth-first search
- order.
-
- BRANCH is a predicate of one argument that returns non-nil if the
- passed argument is a branch, that is, a node that can have
- children.
-
- CHILDREN is a function of one argument that returns the children of
- the passed branch node.
-
- Non-branch nodes are simply copied.
-
- (-tree-seq 'listp 'identity '(1 (2 3) 4 (5 (6 7))))
- ⇒ '((1 (2 3) 4 (5 (6 7))) 1 (2 3) 2 3 4 (5 (6 7)) 5 (6 7) 6 7)
- (-tree-seq 'listp 'reverse '(1 (2 3) 4 (5 (6 7))))
- ⇒ '((1 (2 3) 4 (5 (6 7))) (5 (6 7)) (6 7) 7 6 5 4 (2 3) 3 2 1)
- (--tree-seq (vectorp it) (append it nil) [1 [2 3] 4 [5 [6 7]]])
- ⇒ '([1 [2 3] 4 [5 [6 7]]] 1 [2 3] 2 3 4 [5 [6 7]] 5 [6 7] 6 7)
-
- -- Function: -tree-map (fn tree)
- Apply FN to each element of TREE while preserving the tree
- structure.
-
- (-tree-map '1+ '(1 (2 3) (4 (5 6) 7)))
- ⇒ '(2 (3 4) (5 (6 7) 8))
- (-tree-map '(lambda (x) (cons x (expt 2 x))) '(1 (2 3) 4))
- ⇒ '((1 . 2) ((2 . 4) (3 . 8)) (4 . 16))
- (--tree-map (length it) '("<body>" ("<p>" "text" "</p>") "</body>"))
- ⇒ '(6 (3 4 4) 7)
-
- -- Function: -tree-map-nodes (pred fun tree)
- Call FUN on each node of TREE that satisfies PRED.
-
- If PRED returns nil, continue descending down this node. If PRED
- returns non-nil, apply FUN to this node and do not descend further.
-
- (-tree-map-nodes 'vectorp (lambda (x) (-sum (append x nil))) '(1 [2 3] 4 (5 [6 7] 8)))
- ⇒ '(1 5 4 (5 13 8))
- (-tree-map-nodes 'keywordp (lambda (x) (symbol-name x)) '(1 :foo 4 ((5 6 :bar) :baz 8)))
- ⇒ '(1 ":foo" 4 ((5 6 ":bar") ":baz" 8))
- (--tree-map-nodes (eq (car-safe it) 'add-mode) (-concat it (list :mode 'emacs-lisp-mode)) '(with-mode emacs-lisp-mode (foo bar) (add-mode a b) (baz (add-mode c d))))
- ⇒ '(with-mode emacs-lisp-mode (foo bar) (add-mode a b :mode emacs-lisp-mode) (baz (add-mode c d :mode emacs-lisp-mode)))
-
- -- Function: -tree-reduce (fn tree)
- Use FN to reduce elements of list TREE. If elements of TREE are
- lists themselves, apply the reduction recursively.
-
- FN is first applied to first element of the list and second
- element, then on this result and third element from the list etc.
-
- See ‘-reduce-r’ (*note -reduce-r::) for how exactly are lists of
- zero or one element handled.
-
- (-tree-reduce '+ '(1 (2 3) (4 5)))
- ⇒ 15
- (-tree-reduce 'concat '("strings" (" on" " various") ((" levels"))))
- ⇒ "strings on various levels"
- (--tree-reduce (cond ((stringp it) (concat it " " acc)) (t (let ((sn (symbol-name it))) (concat "<" sn ">" acc "</" sn ">")))) '(body (p "some words") (div "more" (b "bold") "words")))
- ⇒ "<body><p>some words</p> <div>more <b>bold</b> words</div></body>"
-
- -- Function: -tree-reduce-from (fn init-value tree)
- Use FN to reduce elements of list TREE. If elements of TREE are
- lists themselves, apply the reduction recursively.
-
- FN is first applied to INIT-VALUE and first element of the list,
- then on this result and second element from the list etc.
-
- The initial value is ignored on cons pairs as they always contain
- two elements.
-
- (-tree-reduce-from '+ 1 '(1 (1 1) ((1))))
- ⇒ 8
- (--tree-reduce-from (-concat acc (list it)) nil '(1 (2 3 (4 5)) (6 7)))
- ⇒ '((7 6) ((5 4) 3 2) 1)
-
- -- Function: -tree-mapreduce (fn folder tree)
- Apply FN to each element of TREE, and make a list of the results.
- If elements of TREE are lists themselves, apply FN recursively to
- elements of these nested lists.
-
- Then reduce the resulting lists using FOLDER and initial value
- INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::).
-
- This is the same as calling ‘-tree-reduce’ (*note -tree-reduce::)
- after ‘-tree-map’ (*note -tree-map::) but is twice as fast as it
- only traverse the structure once.
-
- (-tree-mapreduce 'list 'append '(1 (2 (3 4) (5 6)) (7 (8 9))))
- ⇒ '(1 2 3 4 5 6 7 8 9)
- (--tree-mapreduce 1 (+ it acc) '(1 (2 (4 9) (2 1)) (7 (4 3))))
- ⇒ 9
- (--tree-mapreduce 0 (max acc (1+ it)) '(1 (2 (4 9) (2 1)) (7 (4 3))))
- ⇒ 3
-
- -- Function: -tree-mapreduce-from (fn folder init-value tree)
- Apply FN to each element of TREE, and make a list of the results.
- If elements of TREE are lists themselves, apply FN recursively to
- elements of these nested lists.
-
- Then reduce the resulting lists using FOLDER and initial value
- INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::).
-
- This is the same as calling ‘-tree-reduce-from’ (*note
- -tree-reduce-from::) after ‘-tree-map’ (*note -tree-map::) but is
- twice as fast as it only traverse the structure once.
-
- (-tree-mapreduce-from 'identity '* 1 '(1 (2 (3 4) (5 6)) (7 (8 9))))
- ⇒ 362880
- (--tree-mapreduce-from (+ it it) (cons it acc) nil '(1 (2 (4 9) (2 1)) (7 (4 3))))
- ⇒ '(2 (4 (8 18) (4 2)) (14 (8 6)))
- (concat "{" (--tree-mapreduce-from (cond ((-cons-pair? it) (concat (symbol-name (car it)) " -> " (symbol-name (cdr it)))) (t (concat (symbol-name it) " : {"))) (concat it (unless (or (equal acc "}") (equal (substring it (1- (length it))) "{")) ", ") acc) "}" '((elips-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam)))))
- ⇒ "{elips-mode : {foo : {bar -> booze{, baz -> qux{, c-mode : {foo -> bla, bum -> bam}}"
-
- -- Function: -clone (list)
- Create a deep copy of LIST. The new list has the same elements and
- structure but all cons are replaced with new ones. This is useful
- when you need to clone a structure such as plist or alist.
-
- (let* ((a '(1 2 3)) (b (-clone a))) (nreverse a) b)
- ⇒ '(1 2 3)
-
-\1f
-File: dash.info, Node: Threading macros, Next: Binding, Prev: Tree operations, Up: Functions
-
-2.12 Threading macros
-=====================
-
- -- Macro: -> (x &optional form &rest more)
- Thread the expr through the forms. Insert X as the second item in
- the first form, making a list of it if it is not a list already.
- If there are more forms, insert the first form as the second item
- in second form, etc.
-
- (-> '(2 3 5))
- ⇒ '(2 3 5)
- (-> '(2 3 5) (append '(8 13)))
- ⇒ '(2 3 5 8 13)
- (-> '(2 3 5) (append '(8 13)) (-slice 1 -1))
- ⇒ '(3 5 8)
-
- -- Macro: ->> (x &optional form &rest more)
- Thread the expr through the forms. Insert X as the last item in
- the first form, making a list of it if it is not a list already.
- If there are more forms, insert the first form as the last item in
- second form, etc.
-
- (->> '(1 2 3) (-map 'square))
- ⇒ '(1 4 9)
- (->> '(1 2 3) (-map 'square) (-remove 'even?))
- ⇒ '(1 9)
- (->> '(1 2 3) (-map 'square) (-reduce '+))
- ⇒ 14
-
- -- Macro: --> (x &rest forms)
- Starting with the value of X, thread each expression through FORMS.
-
- Insert X at the position signified by the symbol ‘it’ in the first
- form. If there are more forms, insert the first form at the
- position signified by ‘it’ in in second form, etc.
-
- (--> "def" (concat "abc" it "ghi"))
- ⇒ "abcdefghi"
- (--> "def" (concat "abc" it "ghi") (upcase it))
- ⇒ "ABCDEFGHI"
- (--> "def" (concat "abc" it "ghi") upcase)
- ⇒ "ABCDEFGHI"
-
- -- Macro: -as-> (value variable &rest forms)
- Starting with VALUE, thread VARIABLE through FORMS.
-
- In the first form, bind VARIABLE to VALUE. In the second form,
- bind VARIABLE to the result of the first form, and so forth.
-
- (-as-> 3 my-var (1+ my-var) (list my-var) (mapcar (lambda (ele) (* 2 ele)) my-var))
- ⇒ '(8)
- (-as-> 3 my-var 1+)
- ⇒ 4
- (-as-> 3 my-var)
- ⇒ 3
-
- -- Macro: -some-> (x &optional form &rest more)
- When expr is non-nil, thread it through the first form (via ‘->’
- (*note ->::)), and when that result is non-nil, through the next
- form, etc.
-
- (-some-> '(2 3 5))
- ⇒ '(2 3 5)
- (-some-> 5 square)
- ⇒ 25
- (-some-> 5 even? square)
- ⇒ nil
-
- -- Macro: -some->> (x &optional form &rest more)
- When expr is non-nil, thread it through the first form (via ‘->>’
- (*note ->>::)), and when that result is non-nil, through the next
- form, etc.
-
- (-some->> '(1 2 3) (-map 'square))
- ⇒ '(1 4 9)
- (-some->> '(1 3 5) (-last 'even?) (+ 100))
- ⇒ nil
- (-some->> '(2 4 6) (-last 'even?) (+ 100))
- ⇒ 106
-
- -- Macro: -some--> (x &optional form &rest more)
- When expr in non-nil, thread it through the first form (via ‘-->’
- (*note -->::)), and when that result is non-nil, through the next
- form, etc.
-
- (-some--> "def" (concat "abc" it "ghi"))
- ⇒ "abcdefghi"
- (-some--> nil (concat "abc" it "ghi"))
- ⇒ nil
- (-some--> '(1 3 5) (-filter 'even? it) (append it it) (-map 'square it))
- ⇒ nil
-
-\1f
-File: dash.info, Node: Binding, Next: Side-effects, Prev: Threading macros, Up: Functions
-
-2.13 Binding
-============
-
-Convenient versions of ‘let‘ and ‘let*‘ constructs combined with flow
-control.
-
- -- Macro: -when-let (var-val &rest body)
- If VAL evaluates to non-nil, bind it to VAR and execute body.
-
- Note: binding is done according to ‘-let’ (*note -let::).
-
- (fn (VAR VAL) &rest BODY)
-
- (-when-let (match-index (string-match "d" "abcd")) (+ match-index 2))
- ⇒ 5
- (-when-let ((&plist :foo foo) (list :foo "foo")) foo)
- ⇒ "foo"
- (-when-let ((&plist :foo foo) (list :bar "bar")) foo)
- ⇒ nil
-
- -- Macro: -when-let* (vars-vals &rest body)
- If all VALS evaluate to true, bind them to their corresponding VARS
- and execute body. VARS-VALS should be a list of (VAR VAL) pairs.
-
- Note: binding is done according to ‘-let*’ (*note -let*::). VALS
- are evaluated sequentially, and evaluation stops after the first
- nil VAL is encountered.
-
- (-when-let* ((x 5) (y 3) (z (+ y 4))) (+ x y z))
- ⇒ 15
- (-when-let* ((x 5) (y nil) (z 7)) (+ x y z))
- ⇒ nil
-
- -- Macro: -if-let (var-val then &rest else)
- If VAL evaluates to non-nil, bind it to VAR and do THEN, otherwise
- do ELSE.
-
- Note: binding is done according to ‘-let’ (*note -let::).
-
- (fn (VAR VAL) THEN &rest ELSE)
-
- (-if-let (match-index (string-match "d" "abc")) (+ match-index 3) 7)
- ⇒ 7
- (--if-let (even? 4) it nil)
- ⇒ t
-
- -- Macro: -if-let* (vars-vals then &rest else)
- If all VALS evaluate to true, bind them to their corresponding VARS
- and do THEN, otherwise do ELSE. VARS-VALS should be a list of (VAR
- VAL) pairs.
-
- Note: binding is done according to ‘-let*’ (*note -let*::). VALS
- are evaluated sequentially, and evaluation stops after the first
- nil VAL is encountered.
-
- (-if-let* ((x 5) (y 3) (z 7)) (+ x y z) "foo")
- ⇒ 15
- (-if-let* ((x 5) (y nil) (z 7)) (+ x y z) "foo")
- ⇒ "foo"
- (-if-let* (((_ _ x) '(nil nil 7))) x)
- ⇒ 7
-
- -- Macro: -let (varlist &rest body)
- Bind variables according to VARLIST then eval BODY.
-
- VARLIST is a list of lists of the form (PATTERN SOURCE). Each
- PATTERN is matched against the SOURCE "structurally". SOURCE is
- only evaluated once for each PATTERN. Each PATTERN is matched
- recursively, and can therefore contain sub-patterns which are
- matched against corresponding sub-expressions of SOURCE.
-
- All the SOURCEs are evalled before any symbols are bound (i.e. "in
- parallel").
-
- If VARLIST only contains one (PATTERN SOURCE) element, you can
- optionally specify it using a vector and discarding the outer-most
- parens. Thus
-
- (-let ((PATTERN SOURCE)) ..)
-
- becomes
-
- (-let [PATTERN SOURCE] ..).
-
- ‘-let’ (*note -let::) uses a convention of not binding places
- (symbols) starting with _ whenever it’s possible. You can use this
- to skip over entries you don’t care about. However, this is not
- *always* possible (as a result of implementation) and these symbols
- might get bound to undefined values.
-
- Following is the overview of supported patterns. Remember that
- patterns can be matched recursively, so every a, b, aK in the
- following can be a matching construct and not necessarily a
- symbol/variable.
-
- Symbol:
-
- a - bind the SOURCE to A. This is just like regular ‘let’.
-
- Conses and lists:
-
- (a) - bind ‘car’ of cons/list to A
-
- (a . b) - bind car of cons to A and ‘cdr’ to B
-
- (a b) - bind car of list to A and ‘cadr’ to B
-
- (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3
- ...
-
- (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to
- REST.
-
- Vectors:
-
- [a] - bind 0th element of a non-list sequence to A (works with
- vectors, strings, bit arrays...)
-
- [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st
- to A1, 2nd to A2, ... If the PATTERN is shorter than SOURCE, the
- values at places not in PATTERN are ignored. If the PATTERN is
- longer than SOURCE, an ‘error’ is thrown.
-
- [a1 a2 a3 ... &rest rest] - as above, but bind the rest of the
- sequence to REST. This is conceptually the same as improper list
- matching (a1 a2 ... aN . rest)
-
- Key/value stores:
-
- (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE plist to aK. If the value is not found, aK is nil. Uses
- ‘plist-get’ to fetch values.
-
- (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE alist to aK. If the value is not found, aK is nil. Uses
- ‘assoc’ to fetch values.
-
- (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE hash table to aK. If the value is not found, aK is nil.
- Uses ‘gethash’ to fetch values.
-
- Further, special keyword &keys supports "inline" matching of
- plist-like key-value pairs, similarly to &keys keyword of
- ‘cl-defun’.
-
- (a1 a2 ... aN &keys key1 b1 ... keyN bK)
-
- This binds N values from the list to a1 ... aN, then interprets
- the cdr as a plist (see key/value matching above).
-
- A shorthand notation for kv-destructuring exists which allows the
- patterns be optionally left out and derived from the key name in
- the following fashion:
-
- - a key :foo is converted into ‘foo’ pattern, - a key ’bar is
- converted into ‘bar’ pattern, - a key "baz" is converted into ‘baz’
- pattern.
-
- That is, the entire value under the key is bound to the derived
- variable without any further destructuring.
-
- This is possible only when the form following the key is not a
- valid pattern (i.e. not a symbol, a cons cell or a vector).
- Otherwise the matching proceeds as usual and in case of an invalid
- spec fails with an error.
-
- Thus the patterns are normalized as follows:
-
- ;; derive all the missing patterns (&plist :foo ’bar "baz") =>
- (&plist :foo foo ’bar bar "baz" baz)
-
- ;; we can specify some but not others (&plist :foo ’bar
- explicit-bar) => (&plist :foo foo ’bar explicit-bar)
-
- ;; nothing happens, we store :foo in x (&plist :foo x) => (&plist
- :foo x)
-
- ;; nothing happens, we match recursively (&plist :foo (a b c)) =>
- (&plist :foo (a b c))
-
- You can name the source using the syntax SYMBOL &as PATTERN. This
- syntax works with lists (proper or improper), vectors and all types
- of maps.
-
- (list &as a b c) (list 1 2 3)
-
- binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
-
- Similarly:
-
- (bounds &as beg . end) (cons 1 2)
-
- binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
-
- (items &as first . rest) (list 1 2 3)
-
- binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
-
- [vect &as _ b c] [1 2 3]
-
- binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as
- usual).
-
- (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
-
- binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and
- &hash.
-
- This is especially useful when we want to capture the result of a
- computation and destructure at the same time. Consider the form
- (function-returning-complex-structure) returning a list of two
- vectors with two items each. We want to capture this entire result
- and pass it to another computation, but at the same time we want to
- get the second item from each vector. We can achieve it with
- pattern
-
- (result &as [_ a] [_ b]) (function-returning-complex-structure)
-
- Note: Clojure programmers may know this feature as the ":as
- binding". The difference is that we put the &as at the front
- because we need to support improper list binding.
-
- (-let (([a (b c) d] [1 (2 3) 4])) (list a b c d))
- ⇒ '(1 2 3 4)
- (-let [(a b c . d) (list 1 2 3 4 5 6)] (list a b c d))
- ⇒ '(1 2 3 (4 5 6))
- (-let [(&plist :foo foo :bar bar) (list :baz 3 :foo 1 :qux 4 :bar 2)] (list foo bar))
- ⇒ '(1 2)
-
- -- Macro: -let* (varlist &rest body)
- Bind variables according to VARLIST then eval BODY.
-
- VARLIST is a list of lists of the form (PATTERN SOURCE). Each
- PATTERN is matched against the SOURCE structurally. SOURCE is only
- evaluated once for each PATTERN.
-
- Each SOURCE can refer to the symbols already bound by this VARLIST.
- This is useful if you want to destructure SOURCE recursively but
- also want to name the intermediate structures.
-
- See ‘-let’ (*note -let::) for the list of all possible patterns.
-
- (-let* (((a . b) (cons 1 2)) ((c . d) (cons 3 4))) (list a b c d))
- ⇒ '(1 2 3 4)
- (-let* (((a . b) (cons 1 (cons 2 3))) ((c . d) b)) (list a b c d))
- ⇒ '(1 (2 . 3) 2 3)
- (-let* (((&alist "foo" foo "bar" bar) (list (cons "foo" 1) (cons "bar" (list 'a 'b 'c)))) ((a b c) bar)) (list foo a b c bar))
- ⇒ '(1 a b c (a b c))
-
- -- Macro: -lambda (match-form &rest body)
- Return a lambda which destructures its input as MATCH-FORM and
- executes BODY.
-
- Note that you have to enclose the MATCH-FORM in a pair of parens,
- such that:
-
- (-lambda (x) body) (-lambda (x y ...) body)
-
- has the usual semantics of ‘lambda’. Furthermore, these get
- translated into normal lambda, so there is no performance penalty.
-
- See ‘-let’ (*note -let::) for the description of destructuring
- mechanism.
-
- (-map (-lambda ((x y)) (+ x y)) '((1 2) (3 4) (5 6)))
- ⇒ '(3 7 11)
- (-map (-lambda ([x y]) (+ x y)) '([1 2] [3 4] [5 6]))
- ⇒ '(3 7 11)
- (funcall (-lambda ((_ . a) (_ . b)) (-concat a b)) '(1 2 3) '(4 5 6))
- ⇒ '(2 3 5 6)
-
- -- Macro: -setq (&rest forms)
- Bind each MATCH-FORM to the value of its VAL.
-
- MATCH-FORM destructuring is done according to the rules of ‘-let’
- (*note -let::).
-
- This macro allows you to bind multiple variables by destructuring
- the value, so for example:
-
- (-setq (a b) x (&plist :c c) plist)
-
- expands roughly speaking to the following code
-
- (setq a (car x) b (cadr x) c (plist-get plist :c))
-
- Care is taken to only evaluate each VAL once so that in case of
- multiple assignments it does not cause unexpected side effects.
-
- (fn [MATCH-FORM VAL]...)
-
- (progn (-setq a 1) a)
- ⇒ 1
- (progn (-setq (a b) (list 1 2)) (list a b))
- ⇒ '(1 2)
- (progn (-setq (&plist :c c) (list :c "c")) c)
- ⇒ "c"
-
-\1f
-File: dash.info, Node: Side-effects, Next: Destructive operations, Prev: Binding, Up: Functions
-
-2.14 Side-effects
-=================
-
-Functions iterating over lists for side-effect only.
-
- -- Function: -each (list fn)
- Call FN with every item in LIST. Return nil, used for side-effects
- only.
-
- (let (s) (-each '(1 2 3) (lambda (item) (setq s (cons item s)))))
- ⇒ nil
- (let (s) (-each '(1 2 3) (lambda (item) (setq s (cons item s)))) s)
- ⇒ '(3 2 1)
- (let (s) (--each '(1 2 3) (setq s (cons it s))) s)
- ⇒ '(3 2 1)
-
- -- Function: -each-while (list pred fn)
- Call FN with every item in LIST while (PRED item) is non-nil.
- Return nil, used for side-effects only.
-
- (let (s) (-each-while '(2 4 5 6) 'even? (lambda (item) (!cons item s))) s)
- ⇒ '(4 2)
- (let (s) (--each-while '(1 2 3 4) (< it 3) (!cons it s)) s)
- ⇒ '(2 1)
-
- -- Function: -each-indexed (list fn)
- Call (FN index item) for each item in LIST.
-
- In the anaphoric form ‘--each-indexed’, the index is exposed as
- symbol ‘it-index’.
-
- See also: ‘-map-indexed’ (*note -map-indexed::).
-
- (let (s) (-each-indexed '(a b c) (lambda (index item) (setq s (cons (list item index) s)))) s)
- ⇒ '((c 2) (b 1) (a 0))
- (let (s) (--each-indexed '(a b c) (setq s (cons (list it it-index) s))) s)
- ⇒ '((c 2) (b 1) (a 0))
-
- -- Function: -each-r (list fn)
- Call FN with every item in LIST in reversed order. Return nil,
- used for side-effects only.
-
- (let (s) (-each-r '(1 2 3) (lambda (item) (setq s (cons item s)))))
- ⇒ nil
- (let (s) (-each-r '(1 2 3) (lambda (item) (setq s (cons item s)))) s)
- ⇒ '(1 2 3)
- (let (s) (--each-r '(1 2 3) (setq s (cons it s))) s)
- ⇒ '(1 2 3)
-
- -- Function: -each-r-while (list pred fn)
- Call FN with every item in reversed LIST while (PRED item) is
- non-nil. Return nil, used for side-effects only.
-
- (let (s) (-each-r-while '(2 4 5 6) 'even? (lambda (item) (!cons item s))) s)
- ⇒ '(6)
- (let (s) (--each-r-while '(1 2 3 4) (>= it 3) (!cons it s)) s)
- ⇒ '(3 4)
-
- -- Function: -dotimes (num fn)
- Repeatedly calls FN (presumably for side-effects) passing in
- integers from 0 through NUM-1.
-
- (let (s) (-dotimes 3 (lambda (n) (!cons n s))) s)
- ⇒ '(2 1 0)
- (let (s) (--dotimes 5 (!cons it s)) s)
- ⇒ '(4 3 2 1 0)
-
- -- Macro: -doto (eval-initial-value &rest forms)
- Eval a form, then insert that form as the 2nd argument to other
- forms. The EVAL-INITIAL-VALUE form is evaluated once. Its result
- is passed to FORMS, which are then evaluated sequentially. Returns
- the target form.
-
- (-doto '(1 2 3) (!cdr) (!cdr))
- ⇒ '(3)
- (-doto '(1 . 2) (setcar 3) (setcdr 4))
- ⇒ '(3 . 4)
-
- -- Macro: --doto (eval-initial-value &rest forms)
- Anaphoric form of ‘-doto’ (*note -doto::). Note: ‘it’ is not
- required in each form.
-
- (gethash "key" (--doto (make-hash-table :test 'equal) (puthash "key" "value" it)))
- ⇒ "value"
-
-\1f
-File: dash.info, Node: Destructive operations, Next: Function combinators, Prev: Side-effects, Up: Functions
-
-2.15 Destructive operations
-===========================
-
- -- Macro: !cons (car cdr)
- Destructive: Set CDR to the cons of CAR and CDR.
-
- (let (l) (!cons 5 l) l)
- ⇒ '(5)
- (let ((l '(3))) (!cons 5 l) l)
- ⇒ '(5 3)
-
- -- Macro: !cdr (list)
- Destructive: Set LIST to the cdr of LIST.
-
- (let ((l '(3))) (!cdr l) l)
- ⇒ '()
- (let ((l '(3 5))) (!cdr l) l)
- ⇒ '(5)
-
-\1f
-File: dash.info, Node: Function combinators, Prev: Destructive operations, Up: Functions
-
-2.16 Function combinators
-=========================
-
-These combinators require Emacs 24 for its lexical scope. So they are
-offered in a separate package: ‘dash-functional‘.
-
- -- Function: -partial (fn &rest args)
- Takes a function FN and fewer than the normal arguments to FN, and
- returns a fn that takes a variable number of additional ARGS. When
- called, the returned function calls FN with ARGS first and then
- additional args.
-
- (funcall (-partial '- 5) 3)
- ⇒ 2
- (funcall (-partial '+ 5 2) 3)
- ⇒ 10
-
- -- Function: -rpartial (fn &rest args)
- Takes a function FN and fewer than the normal arguments to FN, and
- returns a fn that takes a variable number of additional ARGS. When
- called, the returned function calls FN with the additional args
- first and then ARGS.
-
- (funcall (-rpartial '- 5) 8)
- ⇒ 3
- (funcall (-rpartial '- 5 2) 10)
- ⇒ 3
-
- -- Function: -juxt (&rest fns)
- Takes a list of functions and returns a fn that is the
- juxtaposition of those fns. The returned fn takes a variable
- number of args, and returns a list containing the result of
- applying each fn to the args (left-to-right).
-
- (funcall (-juxt '+ '-) 3 5)
- ⇒ '(8 -2)
- (-map (-juxt 'identity 'square) '(1 2 3))
- ⇒ '((1 1) (2 4) (3 9))
-
- -- Function: -compose (&rest fns)
- Takes a list of functions and returns a fn that is the composition
- of those fns. The returned fn takes a variable number of
- arguments, and returns the result of applying each fn to the result
- of applying the previous fn to the arguments (right-to-left).
-
- (funcall (-compose 'square '+) 2 3)
- ⇒ (square (+ 2 3))
- (funcall (-compose 'identity 'square) 3)
- ⇒ (square 3)
- (funcall (-compose 'square 'identity) 3)
- ⇒ (square 3)
-
- -- Function: -applify (fn)
- Changes an n-arity function FN to a 1-arity function that expects a
- list with n items as arguments
-
- (-map (-applify '+) '((1 1 1) (1 2 3) (5 5 5)))
- ⇒ '(3 6 15)
- (-map (-applify (lambda (a b c) `(,a (,b (,c))))) '((1 1 1) (1 2 3) (5 5 5)))
- ⇒ '((1 (1 (1))) (1 (2 (3))) (5 (5 (5))))
- (funcall (-applify '<) '(3 6))
- ⇒ t
-
- -- Function: -on (operator transformer)
- Return a function of two arguments that first applies TRANSFORMER
- to each of them and then applies OPERATOR on the results (in the
- same order).
-
- In types: (b -> b -> c) -> (a -> b) -> a -> a -> c
-
- (-sort (-on '< 'length) '((1 2 3) (1) (1 2)))
- ⇒ '((1) (1 2) (1 2 3))
- (-min-by (-on '> 'length) '((1 2 3) (4) (1 2)))
- ⇒ '(4)
- (-min-by (-on 'string-lessp 'number-to-string) '(2 100 22))
- ⇒ 22
-
- -- Function: -flip (func)
- Swap the order of arguments for binary function FUNC.
-
- In types: (a -> b -> c) -> b -> a -> c
-
- (funcall (-flip '<) 2 1)
- ⇒ t
- (funcall (-flip '-) 3 8)
- ⇒ 5
- (-sort (-flip '<) '(4 3 6 1))
- ⇒ '(6 4 3 1)
-
- -- Function: -const (c)
- Return a function that returns C ignoring any additional arguments.
-
- In types: a -> b -> a
-
- (funcall (-const 2) 1 3 "foo")
- ⇒ 2
- (-map (-const 1) '("a" "b" "c" "d"))
- ⇒ '(1 1 1 1)
- (-sum (-map (-const 1) '("a" "b" "c" "d")))
- ⇒ 4
-
- -- Macro: -cut (&rest params)
- Take n-ary function and n arguments and specialize some of them.
- Arguments denoted by <> will be left unspecialized.
-
- See SRFI-26 for detailed description.
-
- (funcall (-cut list 1 <> 3 <> 5) 2 4)
- ⇒ '(1 2 3 4 5)
- (-map (-cut funcall <> 5) '(1+ 1- (lambda (x) (/ 1.0 x))))
- ⇒ '(6 4 0.2)
- (-map (-cut <> 1 2 3) (list 'list 'vector 'string))
- ⇒ '((1 2 3) [1 2 3] "\ 1\ 2\ 3")
-
- -- Function: -not (pred)
- Take a unary predicate PRED and return a unary predicate that
- returns t if PRED returns nil and nil if PRED returns non-nil.
-
- (funcall (-not 'even?) 5)
- ⇒ t
- (-filter (-not (-partial '< 4)) '(1 2 3 4 5 6 7 8))
- ⇒ '(1 2 3 4)
-
- -- Function: -orfn (&rest preds)
- Take list of unary predicates PREDS and return a unary predicate
- with argument x that returns non-nil if at least one of the PREDS
- returns non-nil on x.
-
- In types: [a -> Bool] -> a -> Bool
-
- (-filter (-orfn 'even? (-partial (-flip '<) 5)) '(1 2 3 4 5 6 7 8 9 10))
- ⇒ '(1 2 3 4 6 8 10)
- (funcall (-orfn 'stringp 'even?) "foo")
- ⇒ t
-
- -- Function: -andfn (&rest preds)
- Take list of unary predicates PREDS and return a unary predicate
- with argument x that returns non-nil if all of the PREDS returns
- non-nil on x.
-
- In types: [a -> Bool] -> a -> Bool
-
- (funcall (-andfn (-cut < <> 10) 'even?) 6)
- ⇒ t
- (funcall (-andfn (-cut < <> 10) 'even?) 12)
- ⇒ nil
- (-filter (-andfn (-not 'even?) (-cut >= 5 <>)) '(1 2 3 4 5 6 7 8 9 10))
- ⇒ '(1 3 5)
-
- -- Function: -iteratefn (fn n)
- Return a function FN composed N times with itself.
-
- FN is a unary function. If you need to use a function of higher
- arity, use ‘-applify’ (*note -applify::) first to turn it into a
- unary function.
-
- With n = 0, this acts as identity function.
-
- In types: (a -> a) -> Int -> a -> a.
-
- This function satisfies the following law:
-
- (funcall (-iteratefn fn n) init) = (-last-item (-iterate fn init
- (1+ n))).
-
- (funcall (-iteratefn (lambda (x) (* x x)) 3) 2)
- ⇒ 256
- (funcall (-iteratefn '1+ 3) 1)
- ⇒ 4
- (funcall (-iteratefn 'cdr 3) '(1 2 3 4 5))
- ⇒ '(4 5)
-
- -- Function: -fixfn (fn &optional equal-test halt-test)
- Return a function that computes the (least) fixpoint of FN.
-
- FN must be a unary function. The returned lambda takes a single
- argument, X, the initial value for the fixpoint iteration. The
- iteration halts when either of the following conditions is
- satisfied:
-
- 1. Iteration converges to the fixpoint, with equality being tested
- using EQUAL-TEST. If EQUAL-TEST is not specified, ‘equal’ is used.
- For functions over the floating point numbers, it may be necessary
- to provide an appropriate appoximate comparison test.
-
- 2. HALT-TEST returns a non-nil value. HALT-TEST defaults to a
- simple counter that returns t after ‘-fixfn-max-iterations’, to
- guard against infinite iteration. Otherwise, HALT-TEST must be a
- function that accepts a single argument, the current value of X,
- and returns non-nil as long as iteration should continue. In this
- way, a more sophisticated convergence test may be supplied by the
- caller.
-
- The return value of the lambda is either the fixpoint or, if
- iteration halted before converging, a cons with car ‘halted’ and
- cdr the final output from HALT-TEST.
-
- In types: (a -> a) -> a -> a.
-
- (funcall (-fixfn 'cos 'approx-equal) 0.7)
- ⇒ 0.7390851332151607
- (funcall (-fixfn (lambda (x) (expt (+ x 10) 0.25))) 2.0)
- ⇒ 1.8555845286409378
- (funcall (-fixfn 'sin 'approx-equal) 0.1)
- ⇒ '(halted . t)
-
- -- Function: -prodfn (&rest fns)
- Take a list of n functions and return a function that takes a list
- of length n, applying i-th function to i-th element of the input
- list. Returns a list of length n.
-
- In types (for n=2): ((a -> b), (c -> d)) -> (a, c) -> (b, d)
-
- This function satisfies the following laws:
-
- (-compose (-prodfn f g ...) (-prodfn f’ g’ ...)) = (-prodfn
- (-compose f f’) (-compose g g’) ...) (-prodfn f g ...) = (-juxt
- (-compose f (-partial ’nth 0)) (-compose g (-partial ’nth 1)) ...)
- (-compose (-prodfn f g ...) (-juxt f’ g’ ...)) = (-juxt (-compose
- f f’) (-compose g g’) ...) (-compose (-partial ’nth n) (-prod f1
- f2 ...)) = (-compose fn (-partial ’nth n))
-
- (funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3))
- ⇒ '(2 1 "3")
- (-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8)))
- ⇒ '((2 1) (4 3) (6 5) (8 7))
- (apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15")))
- ⇒ 18
-
-\1f
-File: dash.info, Node: Development, Next: Index, Prev: Functions, Up: Top
-
-3 Development
-*************
-
-The dash repository is hosted on GitHub:
-<https://github.com/magnars/dash.el>
-
-* Menu:
-
-* Contribute:: How to contribute
-* Changes:: List of significant changes by version
-* Contributors:: List of contributors
-
-\1f
-File: dash.info, Node: Contribute, Next: Changes, Up: Development
-
-3.1 Contribute
-==============
-
-Yes, please do. Pure functions in the list manipulation realm only,
-please. There’s a suite of tests in dev/examples.el, so remember to add
-tests for your function, or it might get broken later.
-
- Run the tests with ‘./run-tests.sh’. Create the docs with
-‘./create-docs.sh’. I highly recommend that you install these as a
-pre-commit hook, so that the tests are always running and the docs are
-always in sync:
-
-cp pre-commit.sh .git/hooks/pre-commit
-
- Oh, and don’t edit ‘README.md’ directly, it is auto-generated.
-Change ‘readme-template.md’ or ‘examples-to-docs.el’ instead. The same
-goes for the info manual.
-
-\1f
-File: dash.info, Node: Changes, Next: Contributors, Prev: Contribute, Up: Development
-
-3.2 Changes
-===========
-
-Changes in 2.10:
-
- • Add ‘-let’ destructuring to ‘-if-let’ and ‘-when-let’ (Fredrik
- Bergroth)
-
-Changes in 2.9:
-
- • Add ‘-let’, ‘-let*’ and ‘-lambda’ with destructuring
- • Add ‘-tree-seq’ and ‘-tree-map-nodes’
- • Add ‘-non-nil’
- • Add ‘-fix’
- • Add ‘-fixfn’ (dash-functional 1.2)
- • Add ‘-copy’ (Wilfred Hughes)
-
-Changes in 2.8:
-
- • Add ‘-butlast’
-
-Changes in 2.7:
-
- • ‘-zip’ now supports more than two lists (Steve Lamb)
- • Add ‘-cycle’, ‘-pad’, ‘-annotate’, ‘-zip-fill’ (Steve Lamb)
- • Add ‘-table’, ‘-table-flat’ (finite cartesian product)
- • Add ‘-flatten-n’
- • ‘-slice’ now supports "step" argument
- • Add functional combinators ‘-iteratefn’, ‘-prodfn’
- • Add ‘-replace’, ‘-splice’, ‘-splice-list’ which generalize
- ‘-replace-at’ and ‘-insert-at’
- • Add ‘-compose’, ‘-iteratefn’ and ‘-prodfn’ (dash-functional 1.1)
-
-Changes in 2.6:
-
- • Add ‘-is-prefix-p’, ‘-is-suffix-p’, ‘-is-infix-p’ (Matus Goljer)
- • Add ‘-iterate’, ‘-unfold’ (Matus Goljer)
- • Add ‘-split-on’, ‘-split-when’ (Matus Goljer)
- • Add ‘-find-last-index’ (Matus Goljer)
- • Add ‘-list’ (Johan Andersson)
-
-Changes in 2.5:
-
- • Add ‘-same-items?’ (Johan Andersson)
- • A few bugfixes
-
-Changes in 2.4:
-
- • Add ‘-snoc’ (Matus Goljer)
- • Add ‘-replace-at’, ‘-update-at’, ‘-remove-at’, and
- ‘-remove-at-indices’ (Matus Goljer)
-
-Changes in 2.3:
-
- • Add tree operations (Matus Goljer)
- • Make font-lock optional
-
-Changes in 2.2:
-
- • Add ‘-compose’ (Christina Whyte)
-
-Changes in 2.1:
-
- • Add indexing operations (Matus Goljer)
-
-Changes in 2.0:
-
- • Split out ‘dash-functional.el’ (Matus Goljer)
- • Add ‘-andfn’, ‘-orfn’, ‘-not’, ‘-cut’, ‘-const’, ‘-flip’ and ‘-on’.
- (Matus Goljer)
- • Fix ‘-min’, ‘-max’, ‘-min-by’ and ‘-max-by’ (Matus Goljer)
-
-Changes in 1.8:
-
- • Add ‘-first-item’ and ‘-last-item’ (Wilfred Hughes)
-
-Changes in 1.7:
-
- • Add ‘-rotate’ (Matus Goljer)
-
-Changes in 1.6:
-
- • Add ‘-min’, ‘-max’, ‘-min-by’ and ‘-max-by’ (Johan Andersson)
-
-Changes in 1.5:
-
- • Add ‘-sum’ and ‘-product’ (Johan Andersson)
-
-Changes in 1.4:
-
- • Add ‘-sort’
- • Add ‘-reduce-r’ (Matus Goljer)
- • Add ‘-reduce-r-from’ (Matus Goljer)
-
-Changes in 1.3:
-
- • Add ‘-partition-in-steps’
- • Add ‘-partition-all-in-steps’
-
-Changes in 1.2:
-
- • Add ‘-last’ (Matus Goljer)
- • Add ‘-insert-at’ (Emanuel Evans)
- • Add ‘-when-let’ and ‘-if-let’ (Emanuel Evans)
- • Add ‘-when-let*’ and ‘-if-let*’ (Emanuel Evans)
- • Some bugfixes
-
-\1f
-File: dash.info, Node: Contributors, Prev: Changes, Up: Development
-
-3.3 Contributors
-================
-
- • Matus Goljer (https://github.com/Fuco1) contributed lots of
- features and functions.
- • Takafumi Arakaki (https://github.com/tkf) contributed ‘-group-by’.
- • tali713 (https://github.com/tali713) is the author of ‘-applify’.
- • VÃctor M. Valenzuela (https://github.com/vemv) contributed
- ‘-repeat’.
- • Nic Ferrier (https://github.com/nicferrier) contributed ‘-cons*’.
- • Wilfred Hughes (https://github.com/Wilfred) contributed ‘-slice’,
- ‘-first-item’ and ‘-last-item’.
- • Emanuel Evans (https://github.com/shosti) contributed ‘-if-let’,
- ‘-when-let’ and ‘-insert-at’.
- • Johan Andersson (https://github.com/rejeep) contributed ‘-sum’,
- ‘-product’ and ‘-same-items?’
- • Christina Whyte (https://github.com/kurisuwhyte) contributed
- ‘-compose’
- • Steve Lamb (https://github.com/steventlamb) contributed ‘-cycle’,
- ‘-pad’, ‘-annotate’, ‘-zip-fill’ and an n-ary version of ‘-zip’.
- • Fredrik Bergroth (https://github.com/fbergroth) made the ‘-if-let’
- family use ‘-let’ destructuring and improved script for generating
- documentation.
- • Mark Oteiza (https://github.com/holomorph) contributed the script
- to create an info manual.
- • Vasilij Schneidermann (https://github.com/wasamasa) contributed
- ‘-some’.
- • William West (https://github.com/occidens) made ‘-fixfn’ more
- robust at handling floats.
-
- Thanks!
-
-\1f
-File: dash.info, Node: Index, Prev: Development, Up: Top
-
-Index
-*****
-
-\0\b[index\0\b]
-* Menu:
-
-* !cdr: Destructive operations.
- (line 14)
-* !cons: Destructive operations.
- (line 6)
-* -->: Threading macros. (line 32)
-* --doto: Side-effects. (line 81)
-* ->: Threading macros. (line 6)
-* ->>: Threading macros. (line 19)
-* -all?: Predicates. (line 18)
-* -andfn: Function combinators.
- (line 138)
-* -annotate: Maps. (line 79)
-* -any?: Predicates. (line 6)
-* -applify: Function combinators.
- (line 55)
-* -as->: Threading macros. (line 46)
-* -butlast: Other list operations.
- (line 340)
-* -clone: Tree operations. (line 122)
-* -common-prefix: Reductions. (line 223)
-* -common-suffix: Reductions. (line 233)
-* -compose: Function combinators.
- (line 42)
-* -concat: List to list. (line 22)
-* -cons*: Other list operations.
- (line 30)
-* -const: Function combinators.
- (line 92)
-* -contains?: Predicates. (line 57)
-* -copy: Maps. (line 134)
-* -count: Reductions. (line 151)
-* -cut: Function combinators.
- (line 104)
-* -cycle: Other list operations.
- (line 168)
-* -difference: Set operations. (line 20)
-* -distinct: Set operations. (line 62)
-* -dotimes: Side-effects. (line 61)
-* -doto: Side-effects. (line 70)
-* -drop: Sublist selection. (line 124)
-* -drop-last: Sublist selection. (line 136)
-* -drop-while: Sublist selection. (line 157)
-* -each: Side-effects. (line 8)
-* -each-indexed: Side-effects. (line 28)
-* -each-r: Side-effects. (line 41)
-* -each-r-while: Side-effects. (line 52)
-* -each-while: Side-effects. (line 19)
-* -elem-index: Indexing. (line 9)
-* -elem-indices: Indexing. (line 21)
-* -fifth-item: Other list operations.
- (line 320)
-* -filter: Sublist selection. (line 8)
-* -find-index: Indexing. (line 32)
-* -find-indices: Indexing. (line 60)
-* -find-last-index: Indexing. (line 46)
-* -first: Other list operations.
- (line 234)
-* -first-item: Other list operations.
- (line 271)
-* -fix: Other list operations.
- (line 376)
-* -fixfn: Function combinators.
- (line 175)
-* -flatten: List to list. (line 33)
-* -flatten-n: List to list. (line 55)
-* -flip: Function combinators.
- (line 80)
-* -fourth-item: Other list operations.
- (line 310)
-* -grade-down: Indexing. (line 81)
-* -grade-up: Indexing. (line 71)
-* -group-by: Partitioning. (line 187)
-* -if-let: Binding. (line 36)
-* -if-let*: Binding. (line 49)
-* -inits: Reductions. (line 203)
-* -insert-at: List to list. (line 109)
-* -interleave: Other list operations.
- (line 68)
-* -interpose: Other list operations.
- (line 58)
-* -intersection: Set operations. (line 32)
-* -is-infix?: Predicates. (line 110)
-* -is-prefix?: Predicates. (line 86)
-* -is-suffix?: Predicates. (line 98)
-* -iterate: Unfolding. (line 9)
-* -iteratefn: Function combinators.
- (line 152)
-* -juxt: Function combinators.
- (line 31)
-* -keep: List to list. (line 8)
-* -lambda: Binding. (line 252)
-* -last: Other list operations.
- (line 261)
-* -last-item: Other list operations.
- (line 330)
-* -let: Binding. (line 65)
-* -let*: Binding. (line 232)
-* -list: Other list operations.
- (line 363)
-* -map: Maps. (line 10)
-* -map-first: Maps. (line 37)
-* -map-indexed: Maps. (line 65)
-* -map-last: Maps. (line 51)
-* -map-when: Maps. (line 21)
-* -mapcat: Maps. (line 123)
-* -max: Reductions. (line 267)
-* -max-by: Reductions. (line 277)
-* -min: Reductions. (line 243)
-* -min-by: Reductions. (line 253)
-* -non-nil: Sublist selection. (line 79)
-* -none?: Predicates. (line 30)
-* -not: Function combinators.
- (line 117)
-* -on: Function combinators.
- (line 66)
-* -only-some?: Predicates. (line 42)
-* -orfn: Function combinators.
- (line 126)
-* -pad: Other list operations.
- (line 179)
-* -partial: Function combinators.
- (line 9)
-* -partition: Partitioning. (line 74)
-* -partition-after-item: Partitioning. (line 177)
-* -partition-after-pred: Partitioning. (line 145)
-* -partition-all: Partitioning. (line 86)
-* -partition-all-in-steps: Partitioning. (line 109)
-* -partition-before-item: Partitioning. (line 167)
-* -partition-before-pred: Partitioning. (line 156)
-* -partition-by: Partitioning. (line 121)
-* -partition-by-header: Partitioning. (line 132)
-* -partition-in-steps: Partitioning. (line 97)
-* -permutations: Set operations. (line 52)
-* -powerset: Set operations. (line 44)
-* -prodfn: Function combinators.
- (line 209)
-* -product: Reductions. (line 181)
-* -reduce: Reductions. (line 46)
-* -reduce-from: Reductions. (line 8)
-* -reduce-r: Reductions. (line 65)
-* -reduce-r-from: Reductions. (line 27)
-* -reductions: Reductions. (line 119)
-* -reductions-from: Reductions. (line 87)
-* -reductions-r: Reductions. (line 135)
-* -reductions-r-from: Reductions. (line 103)
-* -remove: Sublist selection. (line 23)
-* -remove-at: List to list. (line 145)
-* -remove-at-indices: List to list. (line 158)
-* -remove-first: Sublist selection. (line 37)
-* -remove-item: Sublist selection. (line 67)
-* -remove-last: Sublist selection. (line 52)
-* -repeat: Other list operations.
- (line 19)
-* -replace: List to list. (line 67)
-* -replace-at: List to list. (line 120)
-* -replace-first: List to list. (line 81)
-* -replace-last: List to list. (line 95)
-* -rotate: Other list operations.
- (line 8)
-* -rpartial: Function combinators.
- (line 20)
-* -running-product: Reductions. (line 191)
-* -running-sum: Reductions. (line 169)
-* -same-items?: Predicates. (line 72)
-* -second-item: Other list operations.
- (line 286)
-* -select-by-indices: Sublist selection. (line 168)
-* -select-column: Sublist selection. (line 198)
-* -select-columns: Sublist selection. (line 179)
-* -separate: Partitioning. (line 63)
-* -setq: Binding. (line 274)
-* -slice: Sublist selection. (line 85)
-* -snoc: Other list operations.
- (line 44)
-* -some: Other list operations.
- (line 248)
-* -some-->: Threading macros. (line 83)
-* -some->: Threading macros. (line 59)
-* -some->>: Threading macros. (line 71)
-* -sort: Other list operations.
- (line 350)
-* -splice: Maps. (line 90)
-* -splice-list: Maps. (line 110)
-* -split-at: Partitioning. (line 8)
-* -split-on: Partitioning. (line 28)
-* -split-when: Partitioning. (line 46)
-* -split-with: Partitioning. (line 17)
-* -sum: Reductions. (line 159)
-* -table: Other list operations.
- (line 190)
-* -table-flat: Other list operations.
- (line 209)
-* -tails: Reductions. (line 213)
-* -take: Sublist selection. (line 101)
-* -take-last: Sublist selection. (line 112)
-* -take-while: Sublist selection. (line 146)
-* -third-item: Other list operations.
- (line 298)
-* -tree-map: Tree operations. (line 28)
-* -tree-map-nodes: Tree operations. (line 39)
-* -tree-mapreduce: Tree operations. (line 84)
-* -tree-mapreduce-from: Tree operations. (line 103)
-* -tree-reduce: Tree operations. (line 52)
-* -tree-reduce-from: Tree operations. (line 69)
-* -tree-seq: Tree operations. (line 8)
-* -unfold: Unfolding. (line 25)
-* -union: Set operations. (line 8)
-* -unzip: Other list operations.
- (line 146)
-* -update-at: List to list. (line 132)
-* -when-let: Binding. (line 9)
-* -when-let*: Binding. (line 23)
-* -zip: Other list operations.
- (line 95)
-* -zip-fill: Other list operations.
- (line 138)
-* -zip-lists: Other list operations.
- (line 119)
-* -zip-with: Other list operations.
- (line 79)
-
-
-\1f
-Tag Table:
-Node: Top\7f946
-Node: Installation\7f2425
-Node: Using in a package\7f2958
-Node: Syntax highlighting of dash functions\7f3322
-Node: Functions\7f3705
-Node: Maps\7f4916
-Ref: -map\7f5211
-Ref: -map-when\7f5552
-Ref: -map-first\7f6130
-Ref: -map-last\7f6608
-Ref: -map-indexed\7f7081
-Ref: -annotate\7f7561
-Ref: -splice\7f8051
-Ref: -splice-list\7f8832
-Ref: -mapcat\7f9294
-Ref: -copy\7f9670
-Node: Sublist selection\7f9874
-Ref: -filter\7f10067
-Ref: -remove\7f10519
-Ref: -remove-first\7f10925
-Ref: -remove-last\7f11452
-Ref: -remove-item\7f11973
-Ref: -non-nil\7f12368
-Ref: -slice\7f12527
-Ref: -take\7f13059
-Ref: -take-last\7f13367
-Ref: -drop\7f13690
-Ref: -drop-last\7f13963
-Ref: -take-while\7f14223
-Ref: -drop-while\7f14573
-Ref: -select-by-indices\7f14929
-Ref: -select-columns\7f15443
-Ref: -select-column\7f16149
-Node: List to list\7f16613
-Ref: -keep\7f16805
-Ref: -concat\7f17308
-Ref: -flatten\7f17605
-Ref: -flatten-n\7f18364
-Ref: -replace\7f18751
-Ref: -replace-first\7f19214
-Ref: -replace-last\7f19711
-Ref: -insert-at\7f20201
-Ref: -replace-at\7f20528
-Ref: -update-at\7f20918
-Ref: -remove-at\7f21409
-Ref: -remove-at-indices\7f21897
-Node: Reductions\7f22479
-Ref: -reduce-from\7f22648
-Ref: -reduce-r-from\7f23414
-Ref: -reduce\7f24181
-Ref: -reduce-r\7f24910
-Ref: -reductions-from\7f25781
-Ref: -reductions-r-from\7f26496
-Ref: -reductions\7f27221
-Ref: -reductions-r\7f27846
-Ref: -count\7f28481
-Ref: -sum\7f28705
-Ref: -running-sum\7f28894
-Ref: -product\7f29187
-Ref: -running-product\7f29396
-Ref: -inits\7f29709
-Ref: -tails\7f29957
-Ref: -common-prefix\7f30204
-Ref: -common-suffix\7f30501
-Ref: -min\7f30798
-Ref: -min-by\7f31024
-Ref: -max\7f31547
-Ref: -max-by\7f31772
-Node: Unfolding\7f32300
-Ref: -iterate\7f32539
-Ref: -unfold\7f32984
-Node: Predicates\7f33792
-Ref: -any?\7f33916
-Ref: -all?\7f34236
-Ref: -none?\7f34566
-Ref: -only-some?\7f34868
-Ref: -contains?\7f35353
-Ref: -same-items?\7f35742
-Ref: -is-prefix?\7f36127
-Ref: -is-suffix?\7f36450
-Ref: -is-infix?\7f36773
-Node: Partitioning\7f37127
-Ref: -split-at\7f37315
-Ref: -split-with\7f37600
-Ref: -split-on\7f38003
-Ref: -split-when\7f38679
-Ref: -separate\7f39319
-Ref: -partition\7f39761
-Ref: -partition-all\7f40213
-Ref: -partition-in-steps\7f40641
-Ref: -partition-all-in-steps\7f41138
-Ref: -partition-by\7f41623
-Ref: -partition-by-header\7f42005
-Ref: -partition-after-pred\7f42609
-Ref: -partition-before-pred\7f42953
-Ref: -partition-before-item\7f43304
-Ref: -partition-after-item\7f43615
-Ref: -group-by\7f43921
-Node: Indexing\7f44358
-Ref: -elem-index\7f44560
-Ref: -elem-indices\7f44955
-Ref: -find-index\7f45338
-Ref: -find-last-index\7f45827
-Ref: -find-indices\7f46331
-Ref: -grade-up\7f46739
-Ref: -grade-down\7f47142
-Node: Set operations\7f47552
-Ref: -union\7f47735
-Ref: -difference\7f48177
-Ref: -intersection\7f48594
-Ref: -powerset\7f49031
-Ref: -permutations\7f49244
-Ref: -distinct\7f49544
-Node: Other list operations\7f49922
-Ref: -rotate\7f50147
-Ref: -repeat\7f50517
-Ref: -cons*\7f50780
-Ref: -snoc\7f51167
-Ref: -interpose\7f51580
-Ref: -interleave\7f51878
-Ref: -zip-with\7f52247
-Ref: -zip\7f52964
-Ref: -zip-lists\7f53796
-Ref: -zip-fill\7f54497
-Ref: -unzip\7f54820
-Ref: -cycle\7f55565
-Ref: -pad\7f55938
-Ref: -table\7f56261
-Ref: -table-flat\7f57050
-Ref: -first\7f58058
-Ref: -some\7f58430
-Ref: -last\7f58739
-Ref: -first-item\7f59073
-Ref: -second-item\7f59489
-Ref: -third-item\7f59769
-Ref: -fourth-item\7f60047
-Ref: -fifth-item\7f60313
-Ref: -last-item\7f60575
-Ref: -butlast\7f60867
-Ref: -sort\7f61114
-Ref: -list\7f61603
-Ref: -fix\7f61934
-Node: Tree operations\7f62474
-Ref: -tree-seq\7f62670
-Ref: -tree-map\7f63528
-Ref: -tree-map-nodes\7f63971
-Ref: -tree-reduce\7f64821
-Ref: -tree-reduce-from\7f65703
-Ref: -tree-mapreduce\7f66304
-Ref: -tree-mapreduce-from\7f67164
-Ref: -clone\7f68450
-Node: Threading macros\7f68778
-Ref: ->\7f68923
-Ref: ->>\7f69414
-Ref: -->\7f69919
-Ref: -as->\7f70475
-Ref: -some->\7f70930
-Ref: -some->>\7f71304
-Ref: -some-->\7f71740
-Node: Binding\7f72211
-Ref: -when-let\7f72423
-Ref: -when-let*\7f72908
-Ref: -if-let\7f73431
-Ref: -if-let*\7f73826
-Ref: -let\7f74443
-Ref: -let*\7f80533
-Ref: -lambda\7f81473
-Ref: -setq\7f82270
-Node: Side-effects\7f83086
-Ref: -each\7f83280
-Ref: -each-while\7f83687
-Ref: -each-indexed\7f84047
-Ref: -each-r\7f84565
-Ref: -each-r-while\7f84998
-Ref: -dotimes\7f85373
-Ref: -doto\7f85676
-Ref: --doto\7f86104
-Node: Destructive operations\7f86379
-Ref: !cons\7f86552
-Ref: !cdr\7f86758
-Node: Function combinators\7f86953
-Ref: -partial\7f87227
-Ref: -rpartial\7f87623
-Ref: -juxt\7f88026
-Ref: -compose\7f88458
-Ref: -applify\7f89011
-Ref: -on\7f89442
-Ref: -flip\7f89968
-Ref: -const\7f90280
-Ref: -cut\7f90619
-Ref: -not\7f91105
-Ref: -orfn\7f91415
-Ref: -andfn\7f91849
-Ref: -iteratefn\7f92344
-Ref: -fixfn\7f93047
-Ref: -prodfn\7f94609
-Node: Development\7f95677
-Node: Contribute\7f96026
-Node: Changes\7f96774
-Node: Contributors\7f99772
-Node: Index\7f101391
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
+++ /dev/null
-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.
-\1f
-File: dir, Node: Top This is the top of the INFO tree
-
- This (the Directory node) gives a menu of major topics.
- Typing "q" exits, "H" lists all Info commands, "d" returns here,
- "h" gives a primer for first-timers,
- "mEmacs<Return>" visits the Emacs manual, etc.
-
- In Emacs, you can click mouse button 2 on a menu item or cross reference
- to select it.
-
-* Menu:
-
-Emacs
-* Dash: (dash.info). A modern list library for GNU Emacs
--- /dev/null
+;;; dash-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+ (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (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.
+
+If called interactively, enable Dash-Fontify mode if ARG is
+positive, and disable it if ARG is zero or negative. If called
+from Lisp, also enable the mode if ARG is omitted or nil, and
+toggle it if ARG is `toggle'; disable the mode otherwise.
+
+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, enable the mode if
+ARG is omitted or nil.
+
+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)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dash" '("!cdr" "!cons" "--" "->" "-a" "-butlast" "-c" "-d" "-e" "-f" "-gr" "-i" "-keep" "-l" "-m" "-non" "-only-some" "-p" "-r" "-s" "-t" "-u" "-value-to-list" "-when-let" "-zip" "dash-")))
+
+;;;***
+\f
+;;;### (autoloads nil nil ("dash-pkg.el") (0 0 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; dash-autoloads.el ends here
--- /dev/null
+(define-package "dash" "20210101.1712" "A modern list library for Emacs" 'nil :commit "e8ed3d640797a8b816d1d5e2710a960765ab034b" :authors
+ (("Magnar Sveen" . "magnarsNOSPAMgmail.com"))
+ :maintainer
+ ("Magnar Sveen" . "magnarsNOSPAMgmail.com")
+ :keywords
+ ("extensions" "lisp"))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Magnar Sveen <magnarsNOSPAMgmail.com>
+;; Version: 2.17.0
+;; Keywords: extensions, lisp
+
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; A modern list api for Emacs.
+;;
+;; See documentation on https://github.com/magnars/dash.el#functions
+;;
+;; **Please note** The lexical binding in this file is not utilised at the
+;; moment. We will take full advantage of lexical binding in an upcoming 3.0
+;; release of Dash. In the meantime, we've added the pragma to avoid a bug that
+;; you can read more about in https://github.com/magnars/dash.el/issues/130.
+;;
+
+;;; Code:
+
+;; TODO: `gv' was introduced in Emacs 24.3, so remove this and all
+;; calls to `defsetf' when support for earlier versions is dropped.
+(eval-when-compile
+ (unless (fboundp 'gv-define-setter)
+ (require 'cl)))
+
+(defgroup dash ()
+ "Customize group for Dash, a modern list library."
+ :group 'extensions
+ :group 'lisp
+ :prefix "dash-")
+
+(defmacro !cons (car cdr)
+ "Destructive: Set CDR to the cons of CAR and CDR."
+ `(setq ,cdr (cons ,car ,cdr)))
+
+(defmacro !cdr (list)
+ "Destructive: Set LIST to the cdr of LIST."
+ `(setq ,list (cdr ,list)))
+
+(defmacro --each (list &rest body)
+ "Anaphoric form of `-each'."
+ (declare (debug (form body))
+ (indent 1))
+ (let ((l (make-symbol "list")))
+ `(let ((,l ,list)
+ (it-index 0))
+ (while ,l
+ (let ((it (car ,l)))
+ ,@body)
+ (setq it-index (1+ it-index))
+ (!cdr ,l)))))
+
+(defmacro -doto (eval-initial-value &rest forms)
+ "Eval a form, then insert that form as the 2nd argument to other forms.
+The EVAL-INITIAL-VALUE form is evaluated once. Its result is
+passed to FORMS, which are then evaluated sequentially. Returns
+the target form."
+ (declare (indent 1))
+ (let ((retval (make-symbol "value")))
+ `(let ((,retval ,eval-initial-value))
+ ,@(mapcar (lambda (form)
+ (if (sequencep form)
+ `(,(-first-item form) ,retval ,@(cdr form))
+ `(funcall form ,retval)))
+ forms)
+ ,retval)))
+
+(defmacro --doto (eval-initial-value &rest forms)
+ "Anaphoric form of `-doto'.
+Note: `it' is not required in each form."
+ (declare (indent 1))
+ `(let ((it ,eval-initial-value))
+ ,@forms
+ it))
+
+(defun -each (list fn)
+ "Call FN with every item in LIST. Return nil, used for side-effects only."
+ (declare (indent 1))
+ (--each list (funcall fn it)))
+
+(defalias '--each-indexed '--each)
+
+(defun -each-indexed (list fn)
+ "Call (FN index item) for each item in LIST.
+
+In the anaphoric form `--each-indexed', the index is exposed as symbol `it-index'.
+
+See also: `-map-indexed'."
+ (declare (indent 1))
+ (--each list (funcall fn it-index it)))
+
+(defmacro --each-while (list pred &rest body)
+ "Anaphoric form of `-each-while'."
+ (declare (debug (form form body))
+ (indent 2))
+ (let ((l (make-symbol "list")))
+ `(let ((,l ,list)
+ (it-index 0)
+ it)
+ (ignore it)
+ (while (when ,l
+ (setq it (pop ,l))
+ ,pred)
+ ,@body
+ (setq it-index (1+ it-index))))))
+
+(defun -each-while (list pred fn)
+ "Call FN with every item in LIST while (PRED item) is non-nil.
+Return nil, used for side-effects only."
+ (declare (indent 2))
+ (--each-while list (funcall pred it) (funcall fn it)))
+
+(defmacro --each-r (list &rest body)
+ "Anaphoric form of `-each-r'."
+ (declare (debug (form body))
+ (indent 1))
+ (let ((v (make-symbol "vector")))
+ ;; Implementation note: building vector is considerably faster
+ ;; than building a reversed list (vector takes less memory, so
+ ;; there is less GC), plus length comes naturally. In-place
+ ;; 'nreverse' would be faster still, but BODY would be able to see
+ ;; that, even if modification was reversed before we return.
+ `(let* ((,v (vconcat ,list))
+ (it-index (length ,v))
+ it)
+ (while (> it-index 0)
+ (setq it-index (1- it-index))
+ (setq it (aref ,v it-index))
+ ,@body))))
+
+(defun -each-r (list fn)
+ "Call FN with every item in LIST in reversed order.
+ Return nil, used for side-effects only."
+ (--each-r list (funcall fn it)))
+
+(defmacro --each-r-while (list pred &rest body)
+ "Anaphoric form of `-each-r-while'."
+ (declare (debug (form form body))
+ (indent 2))
+ (let ((v (make-symbol "vector")))
+ `(let* ((,v (vconcat ,list))
+ (it-index (length ,v))
+ it)
+ (while (> it-index 0)
+ (setq it-index (1- it-index))
+ (setq it (aref ,v it-index))
+ (if (not ,pred)
+ (setq it-index -1)
+ ,@body)))))
+
+(defun -each-r-while (list pred fn)
+ "Call FN with every item in reversed LIST while (PRED item) is non-nil.
+Return nil, used for side-effects only."
+ (--each-r-while list (funcall pred it) (funcall fn it)))
+
+(defmacro --dotimes (num &rest body)
+ "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1."
+ (declare (debug (form body))
+ (indent 1))
+ (let ((n (make-symbol "num")))
+ `(let ((,n ,num)
+ (it 0))
+ (while (< it ,n)
+ ,@body
+ (setq it (1+ it))))))
+
+(defun -dotimes (num fn)
+ "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1."
+ (declare (indent 1))
+ (--dotimes num (funcall fn it)))
+
+(defun -map (fn list)
+ "Return a new list consisting of the result of applying FN to the items in LIST."
+ (mapcar fn list))
+
+(defmacro --map (form list)
+ "Anaphoric form of `-map'."
+ (declare (debug (form form)))
+ `(mapcar (lambda (it) ,form) ,list))
+
+(defmacro --reduce-from (form initial-value list)
+ "Anaphoric form of `-reduce-from'."
+ (declare (debug (form form form)))
+ `(let ((acc ,initial-value))
+ (--each ,list (setq acc ,form))
+ acc))
+
+(defun -reduce-from (fn initial-value list)
+ "Return the result of applying FN to INITIAL-VALUE and the
+first item in LIST, then applying FN to that result and the 2nd
+item, etc. If LIST contains no items, return INITIAL-VALUE and
+do not call FN.
+
+In the anaphoric form `--reduce-from', the accumulated value is
+exposed as symbol `acc'.
+
+See also: `-reduce', `-reduce-r'"
+ (--reduce-from (funcall fn acc it) initial-value list))
+
+(defmacro --reduce (form list)
+ "Anaphoric form of `-reduce'."
+ (declare (debug (form form)))
+ (let ((lv (make-symbol "list-value")))
+ `(let ((,lv ,list))
+ (if ,lv
+ (--reduce-from ,form (car ,lv) (cdr ,lv))
+ (let (acc it) ,form)))))
+
+(defun -reduce (fn list)
+ "Return the result of applying FN to the first 2 items in LIST,
+then applying FN to that result and the 3rd item, etc. If LIST
+contains no items, return the result of calling FN with no
+arguments. If LIST contains a single item, return that item
+and do not call FN.
+
+In the anaphoric form `--reduce', the accumulated value is
+exposed as symbol `acc'.
+
+See also: `-reduce-from', `-reduce-r'"
+ (if list
+ (-reduce-from fn (car list) (cdr list))
+ (funcall fn)))
+
+(defmacro --reduce-r-from (form initial-value list)
+ "Anaphoric version of `-reduce-r-from'."
+ (declare (debug (form form form)))
+ `(--reduce-from ,form ,initial-value (reverse ,list)))
+
+(defun -reduce-r-from (fn initial-value list)
+ "Replace conses with FN, nil with INITIAL-VALUE and evaluate
+the resulting expression. If LIST is empty, INITIAL-VALUE is
+returned and FN is not called.
+
+Note: this function works the same as `-reduce-from' but the
+operation associates from right instead of from left.
+
+See also: `-reduce-r', `-reduce'"
+ (--reduce-r-from (funcall fn it acc) initial-value list))
+
+(defmacro --reduce-r (form list)
+ "Anaphoric version of `-reduce-r'."
+ (declare (debug (form form)))
+ `(--reduce ,form (reverse ,list)))
+
+(defun -reduce-r (fn list)
+ "Replace conses with FN and evaluate the resulting expression.
+The final nil is ignored. If LIST contains no items, return the
+result of calling FN with no arguments. If LIST contains a single
+item, return that item and do not call FN.
+
+The first argument of FN is the new item, the second is the
+accumulated value.
+
+Note: this function works the same as `-reduce' but the operation
+associates from right instead of from left.
+
+See also: `-reduce-r-from', `-reduce'"
+ (if list
+ (--reduce-r (funcall fn it acc) list)
+ (funcall fn)))
+
+(defun -reductions-from (fn init list)
+ "Return a list of the intermediate values of the reduction.
+
+See `-reduce-from' for explanation of the arguments.
+
+See also: `-reductions', `-reductions-r', `-reduce-r'"
+ (nreverse (--reduce-from (cons (funcall fn (car acc) it) acc) (list init) list)))
+
+(defun -reductions (fn list)
+ "Return a list of the intermediate values of the reduction.
+
+See `-reduce' for explanation of the arguments.
+
+See also: `-reductions-from', `-reductions-r', `-reduce-r'"
+ (and list (-reductions-from fn (car list) (cdr list))))
+
+(defun -reductions-r-from (fn init list)
+ "Return a list of the intermediate values of the reduction.
+
+See `-reduce-r-from' for explanation of the arguments.
+
+See also: `-reductions-r', `-reductions', `-reduce'"
+ (--reduce-r-from (cons (funcall fn it (car acc)) acc) (list init) list))
+
+(defun -reductions-r (fn list)
+ "Return a list of the intermediate values of the reduction.
+
+See `-reduce-r' for explanation of the arguments.
+
+See also: `-reductions-r-from', `-reductions', `-reduce'"
+ (when list
+ (let ((rev (reverse list)))
+ (--reduce-from (cons (funcall fn it (car acc)) acc)
+ (list (car rev))
+ (cdr rev)))))
+
+(defmacro --filter (form list)
+ "Anaphoric form of `-filter'.
+
+See also: `--remove'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each ,list (when ,form (!cons it ,r)))
+ (nreverse ,r))))
+
+(defun -filter (pred list)
+ "Return a new list of the items in LIST for which PRED returns a non-nil value.
+
+Alias: `-select'
+
+See also: `-keep', `-remove'."
+ (--filter (funcall pred it) list))
+
+(defalias '-select '-filter)
+(defalias '--select '--filter)
+
+(defmacro --remove (form list)
+ "Anaphoric form of `-remove'.
+
+See also `--filter'."
+ (declare (debug (form form)))
+ `(--filter (not ,form) ,list))
+
+(defun -remove (pred list)
+ "Return a new list of the items in LIST for which PRED returns nil.
+
+Alias: `-reject'
+
+See also: `-filter'."
+ (--remove (funcall pred it) list))
+
+(defalias '-reject '-remove)
+(defalias '--reject '--remove)
+
+(defun -remove-first (pred list)
+ "Return a new list with the first item matching PRED removed.
+
+Alias: `-reject-first'
+
+See also: `-remove', `-map-first'"
+ (let (front)
+ (while (and list (not (funcall pred (car list))))
+ (push (car list) front)
+ (!cdr list))
+ (if list
+ (-concat (nreverse front) (cdr list))
+ (nreverse front))))
+
+(defmacro --remove-first (form list)
+ "Anaphoric form of `-remove-first'."
+ (declare (debug (form form)))
+ `(-remove-first (lambda (it) ,form) ,list))
+
+(defalias '-reject-first '-remove-first)
+(defalias '--reject-first '--remove-first)
+
+(defun -remove-last (pred list)
+ "Return a new list with the last item matching PRED removed.
+
+Alias: `-reject-last'
+
+See also: `-remove', `-map-last'"
+ (nreverse (-remove-first pred (reverse list))))
+
+(defmacro --remove-last (form list)
+ "Anaphoric form of `-remove-last'."
+ (declare (debug (form form)))
+ `(-remove-last (lambda (it) ,form) ,list))
+
+(defalias '-reject-last '-remove-last)
+(defalias '--reject-last '--remove-last)
+
+(defun -remove-item (item list)
+ "Remove all occurrences of ITEM from LIST.
+
+Comparison is done with `equal'."
+ (declare (pure t) (side-effect-free t))
+ (--remove (equal it item) list))
+
+(defmacro --keep (form list)
+ "Anaphoric form of `-keep'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result"))
+ (m (make-symbol "mapped")))
+ `(let (,r)
+ (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r))))
+ (nreverse ,r))))
+
+(defun -keep (fn list)
+ "Return a new list of the non-nil results of applying FN to the items in LIST.
+
+If you want to select the original items satisfying a predicate use `-filter'."
+ (--keep (funcall fn it) list))
+
+(defun -non-nil (list)
+ "Return all non-nil elements of LIST."
+ (declare (pure t) (side-effect-free t))
+ (-remove 'null list))
+
+(defmacro --map-indexed (form list)
+ "Anaphoric form of `-map-indexed'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each ,list
+ (!cons ,form ,r))
+ (nreverse ,r))))
+
+(defun -map-indexed (fn list)
+ "Return a new list consisting of the result of (FN index item) for each item in LIST.
+
+In the anaphoric form `--map-indexed', the index is exposed as symbol `it-index'.
+
+See also: `-each-indexed'."
+ (--map-indexed (funcall fn it-index it) list))
+
+(defmacro --map-when (pred rep list)
+ "Anaphoric form of `-map-when'."
+ (declare (debug (form form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each ,list (!cons (if ,pred ,rep it) ,r))
+ (nreverse ,r))))
+
+(defun -map-when (pred rep list)
+ "Return a new list where the elements in LIST that do not match the PRED function
+are unchanged, and where the elements in LIST that do match the PRED function are mapped
+through the REP function.
+
+Alias: `-replace-where'
+
+See also: `-update-at'"
+ (--map-when (funcall pred it) (funcall rep it) list))
+
+(defalias '-replace-where '-map-when)
+(defalias '--replace-where '--map-when)
+
+(defun -map-first (pred rep list)
+ "Replace first item in LIST satisfying PRED with result of REP called on this item.
+
+See also: `-map-when', `-replace-first'"
+ (let (front)
+ (while (and list (not (funcall pred (car list))))
+ (push (car list) front)
+ (!cdr list))
+ (if list
+ (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list)))
+ (nreverse front))))
+
+(defmacro --map-first (pred rep list)
+ "Anaphoric form of `-map-first'."
+ `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
+
+(defun -map-last (pred rep list)
+ "Replace last item in LIST satisfying PRED with result of REP called on this item.
+
+See also: `-map-when', `-replace-last'"
+ (nreverse (-map-first pred rep (reverse list))))
+
+(defmacro --map-last (pred rep list)
+ "Anaphoric form of `-map-last'."
+ `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
+
+(defun -replace (old new list)
+ "Replace all OLD items in LIST with NEW.
+
+Elements are compared using `equal'.
+
+See also: `-replace-at'"
+ (declare (pure t) (side-effect-free t))
+ (--map-when (equal it old) new list))
+
+(defun -replace-first (old new list)
+ "Replace the first occurrence of OLD with NEW in LIST.
+
+Elements are compared using `equal'.
+
+See also: `-map-first'"
+ (declare (pure t) (side-effect-free t))
+ (--map-first (equal old it) new list))
+
+(defun -replace-last (old new list)
+ "Replace the last occurrence of OLD with NEW in LIST.
+
+Elements are compared using `equal'.
+
+See also: `-map-last'"
+ (declare (pure t) (side-effect-free t))
+ (--map-last (equal old it) new list))
+
+(defmacro --mapcat (form list)
+ "Anaphoric form of `-mapcat'."
+ (declare (debug (form form)))
+ `(apply 'append (--map ,form ,list)))
+
+(defun -mapcat (fn list)
+ "Return the concatenation of the result of mapping FN over LIST.
+Thus function FN should return a list."
+ (--mapcat (funcall fn it) list))
+
+(defun -flatten (l)
+ "Take a nested list L and return its contents as a single, flat list.
+
+Note that because `nil' represents a list of zero elements (an
+empty list), any mention of nil in L will disappear after
+flattening. If you need to preserve nils, consider `-flatten-n'
+or map them to some unique symbol and then map them back.
+
+Conses of two atoms are considered \"terminals\", that is, they
+aren't flattened further.
+
+See also: `-flatten-n'"
+ (declare (pure t) (side-effect-free t))
+ (if (and (listp l) (listp (cdr l)))
+ (-mapcat '-flatten l)
+ (list l)))
+
+(defmacro --iterate (form init n)
+ "Anaphoric version of `-iterate'."
+ (declare (debug (form form form)))
+ `(-iterate (lambda (it) ,form) ,init ,n))
+
+(defun -flatten-n (num list)
+ "Flatten NUM levels of a nested LIST.
+
+See also: `-flatten'"
+ (declare (pure t) (side-effect-free t))
+ (-last-item (--iterate (--mapcat (-list it) it) list (1+ num))))
+
+(defun -concat (&rest lists)
+ "Return a new list with the concatenation of the elements in the supplied LISTS."
+ (declare (pure t) (side-effect-free t))
+ (apply 'append lists))
+
+(defalias '-copy 'copy-sequence
+ "Create a shallow copy of LIST.
+
+\(fn LIST)")
+
+(defun -splice (pred fun list)
+ "Splice lists generated by FUN in place of elements matching PRED in LIST.
+
+FUN takes the element matching PRED as input.
+
+This function can be used as replacement for `,@' in case you
+need to splice several lists at marked positions (for example
+with keywords).
+
+See also: `-splice-list', `-insert-at'"
+ (let (r)
+ (--each list
+ (if (funcall pred it)
+ (let ((new (funcall fun it)))
+ (--each new (!cons it r)))
+ (!cons it r)))
+ (nreverse r)))
+
+(defmacro --splice (pred form list)
+ "Anaphoric form of `-splice'."
+ `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list))
+
+(defun -splice-list (pred new-list list)
+ "Splice NEW-LIST in place of elements matching PRED in LIST.
+
+See also: `-splice', `-insert-at'"
+ (-splice pred (lambda (_) new-list) list))
+
+(defmacro --splice-list (pred new-list list)
+ "Anaphoric form of `-splice-list'."
+ `(-splice-list (lambda (it) ,pred) ,new-list ,list))
+
+(defun -cons* (&rest args)
+ "Make a new list from the elements of ARGS.
+
+The last 2 members of ARGS are used as the final cons of the
+result so if the final member of ARGS is not a list the result is
+a dotted list."
+ (declare (pure t) (side-effect-free t))
+ (-reduce-r 'cons args))
+
+(defun -snoc (list elem &rest elements)
+ "Append ELEM to the end of the list.
+
+This is like `cons', but operates on the end of list.
+
+If ELEMENTS is non nil, append these to the list as well."
+ (-concat list (list elem) elements))
+
+(defmacro --first (form list)
+ "Anaphoric form of `-first'."
+ (declare (debug (form form)))
+ (let ((n (make-symbol "needle")))
+ `(let (,n)
+ (--each-while ,list (not ,n)
+ (when ,form (setq ,n it)))
+ ,n)))
+
+(defun -first (pred list)
+ "Return the first x in LIST where (PRED x) is non-nil, else nil.
+
+To get the first item in the list no questions asked, use `car'.
+
+Alias: `-find'"
+ (--first (funcall pred it) list))
+
+(defalias '-find '-first)
+(defalias '--find '--first)
+
+(defmacro --some (form list)
+ "Anaphoric form of `-some'."
+ (declare (debug (form form)))
+ (let ((n (make-symbol "needle")))
+ `(let (,n)
+ (--each-while ,list (not ,n)
+ (setq ,n ,form))
+ ,n)))
+
+(defun -some (pred list)
+ "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil.
+
+Alias: `-any'"
+ (--some (funcall pred it) list))
+
+(defalias '-any '-some)
+(defalias '--any '--some)
+
+(defmacro --last (form list)
+ "Anaphoric form of `-last'."
+ (declare (debug (form form)))
+ (let ((n (make-symbol "needle")))
+ `(let (,n)
+ (--each ,list
+ (when ,form (setq ,n it)))
+ ,n)))
+
+(defun -last (pred list)
+ "Return the last x in LIST where (PRED x) is non-nil, else nil."
+ (--last (funcall pred it) list))
+
+(defalias '-first-item 'car
+ "Return the first item of LIST, or nil on an empty list.
+
+See also: `-second-item', `-last-item'.
+
+\(fn LIST)")
+
+;; Ensure that calls to `-first-item' are compiled to a single opcode,
+;; just like `car'.
+(put '-first-item 'byte-opcode 'byte-car)
+(put '-first-item 'byte-compile 'byte-compile-one-arg)
+
+(defalias '-second-item 'cadr
+ "Return the second item of LIST, or nil if LIST is too short.
+
+See also: `-third-item'.
+
+\(fn LIST)")
+
+(defalias '-third-item
+ (if (fboundp 'caddr)
+ #'caddr
+ (lambda (list) (car (cddr list))))
+ "Return the third item of LIST, or nil if LIST is too short.
+
+See also: `-fourth-item'.
+
+\(fn LIST)")
+
+(defun -fourth-item (list)
+ "Return the fourth item of LIST, or nil if LIST is too short.
+
+See also: `-fifth-item'."
+ (declare (pure t) (side-effect-free t))
+ (car (cdr (cdr (cdr list)))))
+
+(defun -fifth-item (list)
+ "Return the fifth item of LIST, or nil if LIST is too short.
+
+See also: `-last-item'."
+ (declare (pure t) (side-effect-free t))
+ (car (cdr (cdr (cdr (cdr list))))))
+
+(defun -last-item (list)
+ "Return the last item of LIST, or nil on an empty list."
+ (declare (pure t) (side-effect-free t))
+ (car (last list)))
+
+;; Use `with-no-warnings' to suppress unbound `-last-item' or
+;; undefined `gv--defsetter' warnings arising from both
+;; `gv-define-setter' and `defsetf' in certain Emacs versions.
+(with-no-warnings
+ (if (fboundp 'gv-define-setter)
+ (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val))
+ (defsetf -last-item (x) (val) `(setcar (last ,x) ,val))))
+
+(defun -butlast (list)
+ "Return a list of all items in list except for the last."
+ ;; no alias as we don't want magic optional argument
+ (declare (pure t) (side-effect-free t))
+ (butlast list))
+
+(defmacro --count (pred list)
+ "Anaphoric form of `-count'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let ((,r 0))
+ (--each ,list (when ,pred (setq ,r (1+ ,r))))
+ ,r)))
+
+(defun -count (pred list)
+ "Counts the number of items in LIST where (PRED item) is non-nil."
+ (--count (funcall pred it) list))
+
+(defun ---truthy? (val)
+ (declare (pure t) (side-effect-free t))
+ (not (null val)))
+
+(defmacro --any? (form list)
+ "Anaphoric form of `-any?'."
+ (declare (debug (form form)))
+ `(---truthy? (--some ,form ,list)))
+
+(defun -any? (pred list)
+ "Return t if (PRED x) is non-nil for any x in LIST, else nil.
+
+Alias: `-any-p', `-some?', `-some-p'"
+ (--any? (funcall pred it) list))
+
+(defalias '-some? '-any?)
+(defalias '--some? '--any?)
+(defalias '-any-p '-any?)
+(defalias '--any-p '--any?)
+(defalias '-some-p '-any?)
+(defalias '--some-p '--any?)
+
+(defmacro --all? (form list)
+ "Anaphoric form of `-all?'."
+ (declare (debug (form form)))
+ (let ((a (make-symbol "all")))
+ `(let ((,a t))
+ (--each-while ,list ,a (setq ,a ,form))
+ (---truthy? ,a))))
+
+(defun -all? (pred list)
+ "Return t if (PRED x) is non-nil for all x in LIST, else nil.
+
+Alias: `-all-p', `-every?', `-every-p'"
+ (--all? (funcall pred it) list))
+
+(defalias '-every? '-all?)
+(defalias '--every? '--all?)
+(defalias '-all-p '-all?)
+(defalias '--all-p '--all?)
+(defalias '-every-p '-all?)
+(defalias '--every-p '--all?)
+
+(defmacro --none? (form list)
+ "Anaphoric form of `-none?'."
+ (declare (debug (form form)))
+ `(--all? (not ,form) ,list))
+
+(defun -none? (pred list)
+ "Return t if (PRED x) is nil for all x in LIST, else nil.
+
+Alias: `-none-p'"
+ (--none? (funcall pred it) list))
+
+(defalias '-none-p '-none?)
+(defalias '--none-p '--none?)
+
+(defmacro --only-some? (form list)
+ "Anaphoric form of `-only-some?'."
+ (declare (debug (form form)))
+ (let ((y (make-symbol "yes"))
+ (n (make-symbol "no")))
+ `(let (,y ,n)
+ (--each-while ,list (not (and ,y ,n))
+ (if ,form (setq ,y t) (setq ,n t)))
+ (---truthy? (and ,y ,n)))))
+
+(defun -only-some? (pred list)
+ "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED.
+Return `nil` both if all items match the predicate or if none of the items match the predicate.
+
+Alias: `-only-some-p'"
+ (--only-some? (funcall pred it) list))
+
+(defalias '-only-some-p '-only-some?)
+(defalias '--only-some-p '--only-some?)
+
+(defun -slice (list from &optional to step)
+ "Return copy of LIST, starting from index FROM to index TO.
+
+FROM or TO may be negative. These values are then interpreted
+modulo the length of the list.
+
+If STEP is a number, only each STEPth item in the resulting
+section is returned. Defaults to 1."
+ (declare (pure t) (side-effect-free t))
+ (let ((length (length list))
+ (new-list nil))
+ ;; to defaults to the end of the list
+ (setq to (or to length))
+ (setq step (or step 1))
+ ;; handle negative indices
+ (when (< from 0)
+ (setq from (mod from length)))
+ (when (< to 0)
+ (setq to (mod to length)))
+
+ ;; iterate through the list, keeping the elements we want
+ (--each-while list (< it-index to)
+ (when (and (>= it-index from)
+ (= (mod (- from it-index) step) 0))
+ (push it new-list)))
+ (nreverse new-list)))
+
+(defmacro --take-while (form list)
+ "Anaphoric form of `-take-while'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each-while ,list ,form (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.
+
+See also: `-drop-while'"
+ (--take-while (funcall pred it) list))
+
+(defmacro --drop-while (form list)
+ "Anaphoric form of `-drop-while'."
+ (declare (debug (form form)))
+ (let ((l (make-symbol "list")))
+ `(let ((,l ,list))
+ (--each-while ,l ,form (pop ,l))
+ (copy-sequence ,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 a copy of the tail of
+LIST starting from its first element for which PRED returns nil.
+
+See also: `-take-while'"
+ (--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 (pure t) (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 (pure t) (side-effect-free t))
+ (copy-sequence (last list n)))
+
+(defun -drop (n list)
+ "Return a copy of the tail of LIST without the first 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-last'"
+ (copy-sequence (nthcdr 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 (pure t) (side-effect-free t))
+ (nbutlast (copy-sequence list) n))
+
+(defun -split-at (n list)
+ "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list."
+ (declare (pure t) (side-effect-free t))
+ (let (result)
+ (--dotimes n
+ (when list
+ (!cons (car list) result)
+ (!cdr list)))
+ (list (nreverse result) list)))
+
+(defun -rotate (n list)
+ "Rotate LIST N places to the right. With N negative, rotate to the left.
+The time complexity is O(n)."
+ (declare (pure t) (side-effect-free t))
+ (when list
+ (let* ((len (length list))
+ (n-mod-len (mod n len))
+ (new-tail-len (- len n-mod-len)))
+ (append (-drop new-tail-len list) (-take new-tail-len list)))))
+
+(defun -insert-at (n x list)
+ "Return a list with X inserted into LIST at position N.
+
+See also: `-splice', `-splice-list'"
+ (declare (pure t) (side-effect-free t))
+ (let ((split-list (-split-at n list)))
+ (nconc (car split-list) (cons x (cadr split-list)))))
+
+(defun -replace-at (n x list)
+ "Return a list with element at Nth position in LIST replaced with X.
+
+See also: `-replace'"
+ (declare (pure t) (side-effect-free t))
+ (let ((split-list (-split-at n list)))
+ (nconc (car split-list) (cons x (cdr (cadr split-list))))))
+
+(defun -update-at (n func list)
+ "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.
+
+See also: `-map-when'"
+ (let ((split-list (-split-at n list)))
+ (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list))))))
+
+(defmacro --update-at (n form list)
+ "Anaphoric version of `-update-at'."
+ (declare (debug (form form form)))
+ `(-update-at ,n (lambda (it) ,form) ,list))
+
+(defun -remove-at (n list)
+ "Return a list with element at Nth position in LIST removed.
+
+See also: `-remove-at-indices', `-remove'"
+ (declare (pure t) (side-effect-free t))
+ (-remove-at-indices (list n) list))
+
+(defun -remove-at-indices (indices list)
+ "Return a list whose elements are elements from LIST without
+elements selected as `(nth i list)` for all i
+from INDICES.
+
+See also: `-remove-at', `-remove'"
+ (declare (pure t) (side-effect-free t))
+ (let* ((indices (-sort '< indices))
+ (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices))))
+ r)
+ (--each diffs
+ (let ((split (-split-at it list)))
+ (!cons (car split) r)
+ (setq list (cdr (cadr split)))))
+ (!cons list r)
+ (apply '-concat (nreverse r))))
+
+(defmacro --split-with (pred list)
+ "Anaphoric form of `-split-with'."
+ (declare (debug (form form)))
+ (let ((l (make-symbol "list"))
+ (r (make-symbol "result"))
+ (c (make-symbol "continue")))
+ `(let ((,l ,list)
+ (,r nil)
+ (,c t))
+ (while (and ,l ,c)
+ (let ((it (car ,l)))
+ (if (not ,pred)
+ (setq ,c nil)
+ (!cons it ,r)
+ (!cdr ,l))))
+ (list (nreverse ,r) ,l))))
+
+(defun -split-with (pred list)
+ "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list."
+ (--split-with (funcall pred it) list))
+
+(defmacro -split-on (item list)
+ "Split the LIST each time ITEM is found.
+
+Unlike `-partition-by', the ITEM is discarded from the results.
+Empty lists are also removed from the result.
+
+Comparison is done by `equal'.
+
+See also `-split-when'"
+ (declare (debug (form form)))
+ `(-split-when (lambda (it) (equal it ,item)) ,list))
+
+(defmacro --split-when (form list)
+ "Anaphoric version of `-split-when'."
+ (declare (debug (form form)))
+ `(-split-when (lambda (it) ,form) ,list))
+
+(defun -split-when (fn list)
+ "Split the LIST on each element where FN returns non-nil.
+
+Unlike `-partition-by', the \"matched\" element is discarded from
+the results. Empty lists are also removed from the result.
+
+This function can be thought of as a generalization of
+`split-string'."
+ (let (r s)
+ (while list
+ (if (not (funcall fn (car list)))
+ (push (car list) s)
+ (when s (push (nreverse s) r))
+ (setq s nil))
+ (!cdr list))
+ (when s (push (nreverse s) r))
+ (nreverse r)))
+
+(defmacro --separate (form list)
+ "Anaphoric form of `-separate'."
+ (declare (debug (form form)))
+ (let ((y (make-symbol "yes"))
+ (n (make-symbol "no")))
+ `(let (,y ,n)
+ (--each ,list (if ,form (!cons it ,y) (!cons it ,n)))
+ (list (nreverse ,y) (nreverse ,n)))))
+
+(defun -separate (pred list)
+ "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list."
+ (--separate (funcall pred it) list))
+
+(defun ---partition-all-in-steps-reversed (n step list)
+ "Private: Used by -partition-all-in-steps and -partition-in-steps."
+ (when (< step 1)
+ (error "Step must be a positive number, or you're looking at some juicy infinite loops."))
+ (let ((result nil))
+ (while list
+ (!cons (-take n list) result)
+ (setq list (-drop step list)))
+ result))
+
+(defun -partition-all-in-steps (n step list)
+ "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
+The last groups may contain less than N items."
+ (declare (pure t) (side-effect-free t))
+ (nreverse (---partition-all-in-steps-reversed n step list)))
+
+(defun -partition-in-steps (n step list)
+ "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
+If there are not enough items to make the last group N-sized,
+those items are discarded."
+ (declare (pure t) (side-effect-free t))
+ (let ((result (---partition-all-in-steps-reversed n step list)))
+ (while (and result (< (length (car result)) n))
+ (!cdr result))
+ (nreverse result)))
+
+(defun -partition-all (n list)
+ "Return a new list with the items in LIST grouped into N-sized sublists.
+The last group may contain less than N items."
+ (declare (pure t) (side-effect-free t))
+ (-partition-all-in-steps n n list))
+
+(defun -partition (n list)
+ "Return a new list with the items in LIST grouped into N-sized sublists.
+If there are not enough items to make the last group N-sized,
+those items are discarded."
+ (declare (pure t) (side-effect-free t))
+ (-partition-in-steps n n list))
+
+(defmacro --partition-by (form list)
+ "Anaphoric form of `-partition-by'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result"))
+ (s (make-symbol "sublist"))
+ (v (make-symbol "value"))
+ (n (make-symbol "new-value"))
+ (l (make-symbol "list")))
+ `(let ((,l ,list))
+ (when ,l
+ (let* ((,r nil)
+ (it (car ,l))
+ (,s (list it))
+ (,v ,form)
+ (,l (cdr ,l)))
+ (while ,l
+ (let* ((it (car ,l))
+ (,n ,form))
+ (unless (equal ,v ,n)
+ (!cons (nreverse ,s) ,r)
+ (setq ,s nil)
+ (setq ,v ,n))
+ (!cons it ,s)
+ (!cdr ,l)))
+ (!cons (nreverse ,s) ,r)
+ (nreverse ,r))))))
+
+(defun -partition-by (fn list)
+ "Apply FN to each item in LIST, splitting it each time FN returns a new value."
+ (--partition-by (funcall fn it) list))
+
+(defmacro --partition-by-header (form list)
+ "Anaphoric form of `-partition-by-header'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result"))
+ (s (make-symbol "sublist"))
+ (h (make-symbol "header-value"))
+ (b (make-symbol "seen-body?"))
+ (n (make-symbol "new-value"))
+ (l (make-symbol "list")))
+ `(let ((,l ,list))
+ (when ,l
+ (let* ((,r nil)
+ (it (car ,l))
+ (,s (list it))
+ (,h ,form)
+ (,b nil)
+ (,l (cdr ,l)))
+ (while ,l
+ (let* ((it (car ,l))
+ (,n ,form))
+ (if (equal ,h ,n)
+ (when ,b
+ (!cons (nreverse ,s) ,r)
+ (setq ,s nil)
+ (setq ,b nil))
+ (setq ,b t))
+ (!cons it ,s)
+ (!cdr ,l)))
+ (!cons (nreverse ,s) ,r)
+ (nreverse ,r))))))
+
+(defun -partition-by-header (fn list)
+ "Apply FN to the first item in LIST. That is the header
+value. Apply FN to each item in LIST, splitting it each time FN
+returns the header value, but only after seeing at least one
+other value (the body)."
+ (--partition-by-header (funcall fn it) list))
+
+(defun -partition-after-pred (pred list)
+ "Partition directly after each time PRED is true on an element of LIST."
+ (when list
+ (let ((rest (-partition-after-pred pred
+ (cdr list))))
+ (if (funcall pred (car list))
+ ;;split after (car list)
+ (cons (list (car list))
+ rest)
+
+ ;;don't split after (car list)
+ (cons (cons (car list)
+ (car rest))
+ (cdr rest))))))
+
+(defun -partition-before-pred (pred list)
+ "Partition directly before each time PRED is true on an element of LIST."
+ (nreverse (-map #'reverse
+ (-partition-after-pred pred (reverse list)))))
+
+(defun -partition-after-item (item list)
+ "Partition directly after each time ITEM appears in LIST."
+ (-partition-after-pred (lambda (ele) (equal ele item))
+ list))
+
+(defun -partition-before-item (item list)
+ "Partition directly before each time ITEM appears in LIST."
+ (-partition-before-pred (lambda (ele) (equal ele item))
+ list))
+
+(defmacro --group-by (form list)
+ "Anaphoric form of `-group-by'."
+ (declare (debug t))
+ (let ((n (make-symbol "n"))
+ (k (make-symbol "k"))
+ (grp (make-symbol "grp")))
+ `(nreverse
+ (-map
+ (lambda (,n)
+ (cons (car ,n)
+ (nreverse (cdr ,n))))
+ (--reduce-from
+ (let* ((,k (,@form))
+ (,grp (assoc ,k acc)))
+ (if ,grp
+ (setcdr ,grp (cons it (cdr ,grp)))
+ (push
+ (list ,k it)
+ acc))
+ acc)
+ nil ,list)))))
+
+(defun -group-by (fn list)
+ "Separate LIST into an alist whose keys are FN applied to the
+elements of LIST. Keys are compared by `equal'."
+ (--group-by (funcall fn it) list))
+
+(defun -interpose (sep list)
+ "Return a new list of all elements in LIST separated by SEP."
+ (declare (pure t) (side-effect-free t))
+ (let (result)
+ (when list
+ (!cons (car list) result)
+ (!cdr list))
+ (while list
+ (setq result (cons (car list) (cons sep result)))
+ (!cdr list))
+ (nreverse result)))
+
+(defun -interleave (&rest lists)
+ "Return a new list of the first item in each list, then the second etc."
+ (declare (pure t) (side-effect-free t))
+ (when lists
+ (let (result)
+ (while (-none? 'null lists)
+ (--each lists (!cons (car it) result))
+ (setq lists (-map 'cdr lists)))
+ (nreverse result))))
+
+(defmacro --zip-with (form list1 list2)
+ "Anaphoric form of `-zip-with'.
+
+The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'."
+ (declare (debug (form form form)))
+ (let ((r (make-symbol "result"))
+ (l1 (make-symbol "list1"))
+ (l2 (make-symbol "list2")))
+ `(let ((,r nil)
+ (,l1 ,list1)
+ (,l2 ,list2))
+ (while (and ,l1 ,l2)
+ (let ((it (car ,l1))
+ (other (car ,l2)))
+ (!cons ,form ,r)
+ (!cdr ,l1)
+ (!cdr ,l2)))
+ (nreverse ,r))))
+
+(defun -zip-with (fn list1 list2)
+ "Zip the two lists LIST1 and LIST2 using a function FN. This
+function is applied pairwise taking as first argument element of
+LIST1 and as second argument element of LIST2 at corresponding
+position.
+
+The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it',
+and the elements from LIST2 as symbol `other'."
+ (--zip-with (funcall fn it other) list1 list2))
+
+(defun -zip-lists (&rest lists)
+ "Zip LISTS together. Group the head of each list, followed by the
+second elements of each list, and so on. The lengths of the returned
+groupings are equal to the length of the shortest input list.
+
+The return value is always list of lists, which is a difference
+from `-zip-pair' which returns a cons-cell in case two input
+lists are provided.
+
+See also: `-zip'"
+ (declare (pure t) (side-effect-free t))
+ (when lists
+ (let (results)
+ (while (-none? 'null lists)
+ (setq results (cons (mapcar 'car lists) results))
+ (setq lists (mapcar 'cdr lists)))
+ (nreverse results))))
+
+(defun -zip (&rest lists)
+ "Zip LISTS together. Group the head of each list, followed by the
+second elements of each list, and so on. The lengths of the returned
+groupings are equal to the length of the shortest input list.
+
+If two lists are provided as arguments, return the groupings as a list
+of cons cells. Otherwise, return the groupings as a list of lists.
+
+Use `-zip-lists' if you need the return value to always be a list
+of lists.
+
+Alias: `-zip-pair'
+
+See also: `-zip-lists'"
+ (declare (pure t) (side-effect-free t))
+ (when lists
+ (let (results)
+ (while (-none? 'null lists)
+ (setq results (cons (mapcar 'car lists) results))
+ (setq lists (mapcar 'cdr lists)))
+ (setq results (nreverse results))
+ (if (= (length lists) 2)
+ ;; to support backward compatibility, return
+ ;; a cons cell if two lists were provided
+ (--map (cons (car it) (cadr it)) results)
+ results))))
+
+(defalias '-zip-pair '-zip)
+
+(defun -zip-fill (fill-value &rest lists)
+ "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
+lengths of the returned groupings are equal to the length of the
+longest input list."
+ (declare (pure t) (side-effect-free t))
+ (apply '-zip (apply '-pad (cons fill-value lists))))
+
+(defun -unzip (lists)
+ "Unzip LISTS.
+
+This works just like `-zip' but takes a list of lists instead of
+a variable number of arguments, such that
+
+ (-unzip (-zip L1 L2 L3 ...))
+
+is identity (given that the lists are the same length).
+
+Note in particular that calling this on a list of two lists will
+return a list of cons-cells such that the above identity works.
+
+See also: `-zip'"
+ (apply '-zip lists))
+
+(defun -cycle (list)
+ "Return an infinite 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)
+ "Appends FILL-VALUE to the end of each list in LISTS such that they
+will all have the same length."
+ (let* ((annotations (-annotate 'length lists))
+ (n (-max (-map 'car annotations))))
+ (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations)))
+
+(defun -annotate (fn list)
+ "Return a list of cons cells where each cell is FN applied to each
+element of LIST paired with the unmodified element of LIST."
+ (-zip (-map fn list) list))
+
+(defmacro --annotate (form list)
+ "Anaphoric version of `-annotate'."
+ (declare (debug (form form)))
+ `(-annotate (lambda (it) ,form) ,list))
+
+(defun dash--table-carry (lists restore-lists &optional re)
+ "Helper for `-table' and `-table-flat'.
+
+If a list overflows, carry to the right and reset the list."
+ (while (not (or (car lists)
+ (equal lists '(nil))))
+ (setcar lists (car restore-lists))
+ (pop (cadr lists))
+ (!cdr lists)
+ (!cdr restore-lists)
+ (when re
+ (push (nreverse (car re)) (cadr re))
+ (setcar re nil)
+ (!cdr re))))
+
+(defun -table (fn &rest lists)
+ "Compute outer product of LISTS using function FN.
+
+The function FN should have the same arity as the number of
+supplied lists.
+
+The outer product is computed by applying fn to all possible
+combinations created by taking one element from each list in
+order. The dimension of the result is (length lists).
+
+See also: `-table-flat'"
+ (let ((restore-lists (copy-sequence lists))
+ (last-list (last lists))
+ (re (make-list (length lists) nil)))
+ (while (car last-list)
+ (let ((item (apply fn (-map 'car lists))))
+ (push item (car re))
+ (setcar lists (cdar lists)) ;; silence byte compiler
+ (dash--table-carry lists restore-lists re)))
+ (nreverse (car (last re)))))
+
+(defun -table-flat (fn &rest lists)
+ "Compute flat outer product of LISTS using function FN.
+
+The function FN should have the same arity as the number of
+supplied lists.
+
+The outer product is computed by applying fn to all possible
+combinations created by taking one element from each list in
+order. The results are flattened, ignoring the tensor structure
+of the result. This is equivalent to calling:
+
+ (-flatten-n (1- (length lists)) (apply \\='-table fn lists))
+
+but the implementation here is much more efficient.
+
+See also: `-flatten-n', `-table'"
+ (let ((restore-lists (copy-sequence lists))
+ (last-list (last lists))
+ re)
+ (while (car last-list)
+ (let ((item (apply fn (-map 'car lists))))
+ (push item re)
+ (setcar lists (cdar lists)) ;; silence byte compiler
+ (dash--table-carry lists restore-lists)))
+ (nreverse re)))
+
+(defun -partial (fn &rest args)
+ "Take a function FN and fewer than the normal arguments to FN,
+and return a fn that takes a variable number of additional ARGS.
+When called, the returned function calls FN with ARGS first and
+then additional args."
+ (apply 'apply-partially fn args))
+
+(defun -elem-index (elem list)
+ "Return the index of the first element in the given LIST which
+is equal to the query element ELEM, or nil if there is no
+such element."
+ (declare (pure t) (side-effect-free t))
+ (car (-elem-indices elem list)))
+
+(defun -elem-indices (elem list)
+ "Return the indices of all elements in LIST equal to the query
+element ELEM, in ascending order."
+ (declare (pure t) (side-effect-free t))
+ (-find-indices (-partial 'equal elem) list))
+
+(defun -find-indices (pred list)
+ "Return the indices of all elements in LIST satisfying the
+predicate PRED, in ascending order."
+ (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list)))
+
+(defmacro --find-indices (form list)
+ "Anaphoric version of `-find-indices'."
+ (declare (debug (form form)))
+ `(-find-indices (lambda (it) ,form) ,list))
+
+(defun -find-index (pred list)
+ "Take a predicate PRED and a LIST and return the index of the
+first element in the list satisfying the predicate, or nil if
+there is no such element.
+
+See also `-first'."
+ (car (-find-indices pred list)))
+
+(defmacro --find-index (form list)
+ "Anaphoric version of `-find-index'."
+ (declare (debug (form form)))
+ `(-find-index (lambda (it) ,form) ,list))
+
+(defun -find-last-index (pred list)
+ "Take a predicate PRED and a LIST and return the index of the
+last element in the list satisfying the predicate, or nil if
+there is no such element.
+
+See also `-last'."
+ (-last-item (-find-indices pred list)))
+
+(defmacro --find-last-index (form list)
+ "Anaphoric version of `-find-last-index'."
+ `(-find-last-index (lambda (it) ,form) ,list))
+
+(defun -select-by-indices (indices list)
+ "Return a list whose elements are elements from LIST selected
+as `(nth i list)` for all i from INDICES."
+ (declare (pure t) (side-effect-free t))
+ (let (r)
+ (--each indices
+ (!cons (nth it list) r))
+ (nreverse r)))
+
+(defun -select-columns (columns table)
+ "Select COLUMNS from TABLE.
+
+TABLE is a list of lists where each element represents one row.
+It is assumed each row has the same length.
+
+Each row is transformed such that only the specified COLUMNS are
+selected.
+
+See also: `-select-column', `-select-by-indices'"
+ (declare (pure t) (side-effect-free t))
+ (--map (-select-by-indices columns it) table))
+
+(defun -select-column (column table)
+ "Select COLUMN from TABLE.
+
+TABLE is a list of lists where each element represents one row.
+It is assumed each row has the same length.
+
+The single selected column is returned as a list.
+
+See also: `-select-columns', `-select-by-indices'"
+ (declare (pure t) (side-effect-free t))
+ (--mapcat (-select-by-indices (list column) it) table))
+
+(defmacro -> (x &optional form &rest more)
+ "Thread the expr through the forms. Insert X as the second item
+in the first form, making a list of it if it is not a list
+already. If there are more forms, insert the first form as the
+second item in second form, etc."
+ (declare (debug (form &rest [&or symbolp (sexp &rest form)])))
+ (cond
+ ((null form) x)
+ ((null more) (if (listp form)
+ `(,(car form) ,x ,@(cdr form))
+ (list form x)))
+ (:else `(-> (-> ,x ,form) ,@more))))
+
+(defmacro ->> (x &optional form &rest more)
+ "Thread the expr through the forms. Insert X as the last item
+in the first form, making a list of it if it is not a list
+already. If there are more forms, insert the first form as the
+last item in second form, etc."
+ (declare (debug ->))
+ (cond
+ ((null form) x)
+ ((null more) (if (listp form)
+ `(,@form ,x)
+ (list form x)))
+ (:else `(->> (->> ,x ,form) ,@more))))
+
+(defmacro --> (x &rest forms)
+ "Starting with the value of X, thread each expression through FORMS.
+
+Insert X at the position signified by the symbol `it' in the first
+form. If there are more forms, insert the first form at the position
+signified by `it' in in second form, etc."
+ (declare (debug (form body)))
+ `(-as-> ,x it ,@forms))
+
+(defmacro -as-> (value variable &rest forms)
+ "Starting with VALUE, thread VARIABLE through FORMS.
+
+In the first form, bind VARIABLE to VALUE. In the second form, bind
+VARIABLE to the result of the first form, and so forth."
+ (declare (debug (form symbolp body)))
+ (if (null forms)
+ `,value
+ `(let ((,variable ,value))
+ (-as-> ,(if (symbolp (car forms))
+ (list (car forms) variable)
+ (car forms))
+ ,variable
+ ,@(cdr forms)))))
+
+(defmacro -some-> (x &optional form &rest more)
+ "When expr is non-nil, thread it through the first form (via `->'),
+and when that result is non-nil, through the next form, etc."
+ (declare (debug ->)
+ (indent 1))
+ (if (null form) x
+ (let ((result (make-symbol "result")))
+ `(-some-> (-when-let (,result ,x)
+ (-> ,result ,form))
+ ,@more))))
+
+(defmacro -some->> (x &optional form &rest more)
+ "When expr is non-nil, thread it through the first form (via `->>'),
+and when that result is non-nil, through the next form, etc."
+ (declare (debug ->)
+ (indent 1))
+ (if (null form) x
+ (let ((result (make-symbol "result")))
+ `(-some->> (-when-let (,result ,x)
+ (->> ,result ,form))
+ ,@more))))
+
+(defmacro -some--> (x &optional form &rest more)
+ "When expr 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))))
+
+(defun -grade-up (comparator list)
+ "Grade elements of LIST using COMPARATOR relation, yielding a
+permutation vector such that applying this permutation to LIST
+sorts it in ascending order."
+ ;; ugly hack to "fix" lack of lexical scope
+ (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other)))))
+ (->> (--map-indexed (cons it it-index) list)
+ (-sort comp)
+ (-map 'cdr))))
+
+(defun -grade-down (comparator list)
+ "Grade elements of LIST using COMPARATOR relation, yielding a
+permutation vector such that applying this permutation to LIST
+sorts it in descending order."
+ ;; ugly hack to "fix" lack of lexical scope
+ (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it)))))
+ (->> (--map-indexed (cons it it-index) list)
+ (-sort comp)
+ (-map 'cdr))))
+
+(defvar dash--source-counter 0
+ "Monotonic counter for generated symbols.")
+
+(defun dash--match-make-source-symbol ()
+ "Generate a new dash-source symbol.
+
+All returned symbols are guaranteed to be unique."
+ (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter))
+ (setq dash--source-counter (1+ dash--source-counter))))
+
+(defun dash--match-ignore-place-p (symbol)
+ "Return non-nil if SYMBOL is a symbol and starts with _."
+ (and (symbolp symbol)
+ (eq (aref (symbol-name symbol) 0) ?_)))
+
+(defun dash--match-cons-skip-cdr (skip-cdr source)
+ "Helper function generating idiomatic shifting code."
+ (cond
+ ((= skip-cdr 0)
+ `(pop ,source))
+ (t
+ `(prog1 ,(dash--match-cons-get-car skip-cdr source)
+ (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source))))))
+
+(defun dash--match-cons-get-car (skip-cdr source)
+ "Helper function generating idiomatic code to get nth car."
+ (cond
+ ((= skip-cdr 0)
+ `(car ,source))
+ ((= skip-cdr 1)
+ `(cadr ,source))
+ (t
+ `(nth ,skip-cdr ,source))))
+
+(defun dash--match-cons-get-cdr (skip-cdr source)
+ "Helper function generating idiomatic code to get nth cdr."
+ (cond
+ ((= skip-cdr 0)
+ source)
+ ((= skip-cdr 1)
+ `(cdr ,source))
+ (t
+ `(nthcdr ,skip-cdr ,source))))
+
+(defun dash--match-cons (match-form source)
+ "Setup a cons matching environment and call the real matcher."
+ (let ((s (dash--match-make-source-symbol))
+ (n 0)
+ (m match-form))
+ (while (and (consp m)
+ (dash--match-ignore-place-p (car m)))
+ (setq n (1+ n)) (!cdr m))
+ (cond
+ ;; when we only have one pattern in the list, we don't have to
+ ;; create a temporary binding (--dash-source--) for the source
+ ;; and just use the input directly
+ ((and (consp m)
+ (not (cdr m)))
+ (dash--match (car m) (dash--match-cons-get-car n source)))
+ ;; handle other special types
+ ((> n 0)
+ (dash--match m (dash--match-cons-get-cdr n source)))
+ ;; this is the only entry-point for dash--match-cons-1, that's
+ ;; why we can't simply use the above branch, it would produce
+ ;; infinite recursion
+ (t
+ (cons (list s source) (dash--match-cons-1 match-form s))))))
+
+(defun dash--get-expand-function (type)
+ "Get expand function name for TYPE."
+ (intern-soft (format "dash-expand:%s" type)))
+
+(defun dash--match-cons-1 (match-form source &optional props)
+ "Match MATCH-FORM against SOURCE.
+
+MATCH-FORM is a proper or improper list. Each element of
+MATCH-FORM is either a symbol, which gets bound to the respective
+value in source or another match form which gets destructured
+recursively.
+
+If the cdr of last cons cell in the list is `nil', matching stops
+there.
+
+SOURCE is a proper or improper list."
+ (let ((skip-cdr (or (plist-get props :skip-cdr) 0)))
+ (cond
+ ((consp match-form)
+ (cond
+ ((cdr match-form)
+ (cond
+ ((and (symbolp (car match-form))
+ (functionp (dash--get-expand-function (car match-form))))
+ (dash--match-kv (dash--match-kv-normalize-match-form match-form) (dash--match-cons-get-cdr skip-cdr source)))
+ ((dash--match-ignore-place-p (car match-form))
+ (dash--match-cons-1 (cdr match-form) source
+ (plist-put props :skip-cdr (1+ skip-cdr))))
+ (t
+ (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source))
+ (dash--match-cons-1 (cdr match-form) source)))))
+ (t ;; Last matching place, no need for shift
+ (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source)))))
+ ((eq match-form nil)
+ nil)
+ (t ;; Handle improper lists. Last matching place, no need for shift
+ (dash--match match-form (dash--match-cons-get-cdr skip-cdr source))))))
+
+(defun dash--vector-tail (seq start)
+ "Return the tail of SEQ starting at START."
+ (cond
+ ((vectorp seq)
+ (let* ((re-length (- (length seq) start))
+ (re (make-vector re-length 0)))
+ (--dotimes re-length (aset re it (aref seq (+ it start))))
+ re))
+ ((stringp seq)
+ (substring seq start))))
+
+(defun dash--match-vector (match-form source)
+ "Setup a vector matching environment and call the real matcher."
+ (let ((s (dash--match-make-source-symbol)))
+ (cond
+ ;; don't bind `s' if we only have one sub-pattern
+ ((= (length match-form) 1)
+ (dash--match (aref match-form 0) `(aref ,source 0)))
+ ;; if the source is a symbol, we don't need to re-bind it
+ ((symbolp source)
+ (dash--match-vector-1 match-form source))
+ ;; don't bind `s' if we only have one sub-pattern which is not ignored
+ ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form))
+ (ignored-places-n (length (-remove 'null ignored-places))))
+ (when (= ignored-places-n (1- (length match-form)))
+ (let ((n (-find-index 'null ignored-places)))
+ (dash--match (aref match-form n) `(aref ,source ,n))))))
+ (t
+ (cons (list s source) (dash--match-vector-1 match-form s))))))
+
+(defun dash--match-vector-1 (match-form source)
+ "Match MATCH-FORM against SOURCE.
+
+MATCH-FORM is a vector. Each element of MATCH-FORM is either a
+symbol, which gets bound to the respective value in source or
+another match form which gets destructured recursively.
+
+If second-from-last place in MATCH-FORM is the symbol &rest, the
+next element of the MATCH-FORM is matched against the tail of
+SOURCE, starting at index of the &rest symbol. This is
+conceptually the same as the (head . tail) match for improper
+lists, where dot plays the role of &rest.
+
+SOURCE is a vector.
+
+If the MATCH-FORM vector is shorter than SOURCE vector, only
+the (length MATCH-FORM) places are bound, the rest of the SOURCE
+is discarded."
+ (let ((i 0)
+ (l (length match-form))
+ (re))
+ (while (< i l)
+ (let ((m (aref match-form i)))
+ (push (cond
+ ((and (symbolp m)
+ (eq m '&rest))
+ (prog1 (dash--match
+ (aref match-form (1+ i))
+ `(dash--vector-tail ,source ,i))
+ (setq i l)))
+ ((and (symbolp m)
+ ;; do not match symbols starting with _
+ (not (eq (aref (symbol-name m) 0) ?_)))
+ (list (list m `(aref ,source ,i))))
+ ((not (symbolp m))
+ (dash--match m `(aref ,source ,i))))
+ re)
+ (setq i (1+ i))))
+ (-flatten-n 1 (nreverse re))))
+
+(defun dash--match-kv-normalize-match-form (pattern)
+ "Normalize kv PATTERN.
+
+This method normalizes PATTERN to the format expected by
+`dash--match-kv'. See `-let' for the specification."
+ (let ((normalized (list (car pattern)))
+ (skip nil)
+ (fill-placeholder (make-symbol "--dash-fill-placeholder--")))
+ (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern)))
+ (lambda (pair)
+ (let ((current (car pair))
+ (next (cdr pair)))
+ (if skip
+ (setq skip nil)
+ (if (or (eq fill-placeholder next)
+ (not (or (and (symbolp next)
+ (not (keywordp next))
+ (not (eq next t))
+ (not (eq next nil)))
+ (and (consp next)
+ (not (eq (car next) 'quote)))
+ (vectorp next))))
+ (progn
+ (cond
+ ((keywordp current)
+ (push current normalized)
+ (push (intern (substring (symbol-name current) 1)) normalized))
+ ((stringp current)
+ (push current normalized)
+ (push (intern current) normalized))
+ ((and (consp current)
+ (eq (car current) 'quote))
+ (push current normalized)
+ (push (cadr current) normalized))
+ (t (error "-let: found key `%s' in kv destructuring but its pattern `%s' is invalid and can not be derived from the key" current next)))
+ (setq skip nil))
+ (push current normalized)
+ (push next normalized)
+ (setq skip t))))))
+ (nreverse normalized)))
+
+(defun dash--match-kv (match-form source)
+ "Setup a kv matching environment and call the real matcher.
+
+kv can be any key-value store, such as plist, alist or hash-table."
+ (let ((s (dash--match-make-source-symbol)))
+ (cond
+ ;; don't bind `s' if we only have one sub-pattern (&type key val)
+ ((= (length match-form) 3)
+ (dash--match-kv-1 (cdr match-form) source (car match-form)))
+ ;; if the source is a symbol, we don't need to re-bind it
+ ((symbolp source)
+ (dash--match-kv-1 (cdr match-form) source (car match-form)))
+ (t
+ (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form)))))))
+
+(defun dash-expand:&hash (key source)
+ "Generate extracting KEY from SOURCE for &hash destructuring."
+ `(gethash ,key ,source))
+
+(defun dash-expand:&plist (key source)
+ "Generate extracting KEY from SOURCE for &plist destructuring."
+ `(plist-get ,source ,key))
+
+(defun dash-expand:&alist (key source)
+ "Generate extracting KEY from SOURCE for &alist destructuring."
+ `(cdr (assoc ,key ,source)))
+
+(defun dash-expand:&hash? (key source)
+ "Generate extracting KEY from SOURCE for &hash? destructuring.
+Similar to &hash but check whether the map is not nil."
+ (let ((src (make-symbol "src")))
+ `(let ((,src ,source))
+ (when ,src (gethash ,key ,src)))))
+
+(defalias 'dash-expand:&keys 'dash-expand:&plist)
+
+(defun dash--match-kv-1 (match-form source type)
+ "Match MATCH-FORM against SOURCE of type TYPE.
+
+MATCH-FORM is a proper list of the form (key1 place1 ... keyN
+placeN). Each placeK is either a symbol, which gets bound to the
+value of keyK retrieved from the key-value store, or another
+match form which gets destructured recursively.
+
+SOURCE is a key-value store of type TYPE, which can be a plist,
+an alist or a hash table.
+
+TYPE is a token specifying the type of the key-value store.
+Valid values are &plist, &alist and &hash."
+ (-flatten-n 1 (-map
+ (lambda (kv)
+ (let* ((k (car kv))
+ (v (cadr kv))
+ (getter
+ (funcall (dash--get-expand-function type) k source)))
+ (cond
+ ((symbolp v)
+ (list (list v getter)))
+ (t (dash--match v getter)))))
+ (-partition 2 match-form))))
+
+(defun dash--match-symbol (match-form source)
+ "Bind a symbol.
+
+This works just like `let', there is no destructuring."
+ (list (list match-form source)))
+
+(defun dash--match (match-form source)
+ "Match MATCH-FORM against SOURCE.
+
+This function tests the MATCH-FORM and dispatches to specific
+matchers based on the type of the expression.
+
+Key-value stores are disambiguated by placing a token &plist,
+&alist or &hash as a first item in the MATCH-FORM."
+ (cond
+ ((symbolp match-form)
+ (dash--match-symbol match-form source))
+ ((consp match-form)
+ (cond
+ ;; Handle the "x &as" bindings first.
+ ((and (consp (cdr match-form))
+ (symbolp (car match-form))
+ (eq '&as (cadr match-form)))
+ (let ((s (car match-form)))
+ (cons (list s source)
+ (dash--match (cddr match-form) s))))
+ ((functionp (dash--get-expand-function (car match-form)))
+ (dash--match-kv (dash--match-kv-normalize-match-form match-form) source))
+ (t (dash--match-cons match-form source))))
+ ((vectorp match-form)
+ ;; We support the &as binding in vectors too
+ (cond
+ ((and (> (length match-form) 2)
+ (symbolp (aref match-form 0))
+ (eq '&as (aref match-form 1)))
+ (let ((s (aref match-form 0)))
+ (cons (list s source)
+ (dash--match (dash--vector-tail match-form 2) s))))
+ (t (dash--match-vector match-form source))))))
+
+(defun dash--normalize-let-varlist (varlist)
+ "Normalize VARLIST so that every binding is a list.
+
+`let' allows specifying a binding which is not a list but simply
+the place which is then automatically bound to nil, such that all
+three of the following are identical and evaluate to nil.
+
+ (let (a) a)
+ (let ((a)) a)
+ (let ((a nil)) a)
+
+This function normalizes all of these to the last form."
+ (--map (if (consp it) it (list it nil)) varlist))
+
+(defmacro -let* (varlist &rest body)
+ "Bind variables according to VARLIST then eval BODY.
+
+VARLIST is a list of lists of the form (PATTERN SOURCE). Each
+PATTERN is matched against the SOURCE structurally. SOURCE is
+only evaluated once for each PATTERN.
+
+Each SOURCE can refer to the symbols already bound by this
+VARLIST. This is useful if you want to destructure SOURCE
+recursively but also want to name the intermediate structures.
+
+See `-let' for the list of all possible patterns."
+ (declare (debug ((&rest [&or (sexp form) sexp]) body))
+ (indent 1))
+ (let* ((varlist (dash--normalize-let-varlist varlist))
+ (bindings (--mapcat (dash--match (car it) (cadr it)) varlist)))
+ `(let* ,bindings
+ ,@body)))
+
+(defmacro -let (varlist &rest body)
+ "Bind variables according to VARLIST then eval BODY.
+
+VARLIST is a list of lists of the form (PATTERN SOURCE). Each
+PATTERN is matched against the SOURCE \"structurally\". SOURCE
+is only evaluated once for each PATTERN. Each PATTERN is matched
+recursively, and can therefore contain sub-patterns which are
+matched against corresponding sub-expressions of SOURCE.
+
+All the SOURCEs are evalled before any symbols are
+bound (i.e. \"in parallel\").
+
+If VARLIST only contains one (PATTERN SOURCE) element, you can
+optionally specify it using a vector and discarding the
+outer-most parens. Thus
+
+ (-let ((PATTERN SOURCE)) ..)
+
+becomes
+
+ (-let [PATTERN SOURCE] ..).
+
+`-let' uses a convention of not binding places (symbols) starting
+with _ whenever it's possible. You can use this to skip over
+entries you don't care about. However, this is not *always*
+possible (as a result of implementation) and these symbols might
+get bound to undefined values.
+
+Following is the overview of supported patterns. Remember that
+patterns can be matched recursively, so every a, b, aK in the
+following can be a matching construct and not necessarily a
+symbol/variable.
+
+Symbol:
+
+ a - bind the SOURCE to A. This is just like regular `let'.
+
+Conses and lists:
+
+ (a) - bind `car' of cons/list to A
+
+ (a . b) - bind car of cons to A and `cdr' to B
+
+ (a b) - bind car of list to A and `cadr' to B
+
+ (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ...
+
+ (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST.
+
+Vectors:
+
+ [a] - bind 0th element of a non-list sequence to A (works with
+ vectors, strings, bit arrays...)
+
+ [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to
+ A1, 2nd to A2, ...
+ If the PATTERN is shorter than SOURCE, the values at
+ places not in PATTERN are ignored.
+ If the PATTERN is longer than SOURCE, an `error' is
+ thrown.
+
+ [a1 a2 a3 ... &rest rest] - as above, but bind the rest of
+ the sequence to REST. This is
+ conceptually the same as improper list
+ matching (a1 a2 ... aN . rest)
+
+Key/value stores:
+
+ (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE plist to aK. If the
+ value is not found, aK is nil.
+ Uses `plist-get' to fetch values.
+
+ (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE alist to aK. If the
+ value is not found, aK is nil.
+ Uses `assoc' to fetch values.
+
+ (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE hash table to aK. If the
+ value is not found, aK is nil.
+ Uses `gethash' to fetch values.
+
+Further, special keyword &keys supports \"inline\" matching of
+plist-like key-value pairs, similarly to &keys keyword of
+`cl-defun'.
+
+ (a1 a2 ... aN &keys key1 b1 ... keyN bK)
+
+This binds N values from the list to a1 ... aN, then interprets
+the cdr as a plist (see key/value matching above).
+
+A shorthand notation for kv-destructuring exists which allows the
+patterns be optionally left out and derived from the key name in
+the following fashion:
+
+- a key :foo is converted into `foo' pattern,
+- a key 'bar is converted into `bar' pattern,
+- a key \"baz\" is converted into `baz' pattern.
+
+That is, the entire value under the key is bound to the derived
+variable without any further destructuring.
+
+This is possible only when the form following the key is not a
+valid pattern (i.e. not a symbol, a cons cell or a vector).
+Otherwise the matching proceeds as usual and in case of an
+invalid spec fails with an error.
+
+Thus the patterns are normalized as follows:
+
+ ;; derive all the missing patterns
+ (&plist :foo 'bar \"baz\") => (&plist :foo foo 'bar bar \"baz\" baz)
+
+ ;; we can specify some but not others
+ (&plist :foo 'bar explicit-bar) => (&plist :foo foo 'bar explicit-bar)
+
+ ;; nothing happens, we store :foo in x
+ (&plist :foo x) => (&plist :foo x)
+
+ ;; nothing happens, we match recursively
+ (&plist :foo (a b c)) => (&plist :foo (a b c))
+
+You can name the source using the syntax SYMBOL &as PATTERN.
+This syntax works with lists (proper or improper), vectors and
+all types of maps.
+
+ (list &as a b c) (list 1 2 3)
+
+binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
+
+Similarly:
+
+ (bounds &as beg . end) (cons 1 2)
+
+binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
+
+ (items &as first . rest) (list 1 2 3)
+
+binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
+
+ [vect &as _ b c] [1 2 3]
+
+binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual).
+
+ (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
+
+binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash.
+
+This is especially useful when we want to capture the result of a
+computation and destructure at the same time. Consider the
+form (function-returning-complex-structure) returning a list of
+two vectors with two items each. We want to capture this entire
+result and pass it to another computation, but at the same time
+we want to get the second item from each vector. We can achieve
+it with pattern
+
+ (result &as [_ a] [_ b]) (function-returning-complex-structure)
+
+Note: Clojure programmers may know this feature as the \":as
+binding\". The difference is that we put the &as at the front
+because we need to support improper list binding."
+ (declare (debug ([&or (&rest [&or (sexp form) sexp])
+ (vector [&rest [sexp form]])]
+ body))
+ (indent 1))
+ (if (vectorp varlist)
+ `(let* ,(dash--match (aref varlist 0) (aref varlist 1))
+ ,@body)
+ (let* ((varlist (dash--normalize-let-varlist varlist))
+ (inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist))
+ (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs))))
+ `(let ,inputs
+ (-let* ,new-varlist ,@body)))))
+
+(defmacro -lambda (match-form &rest body)
+ "Return a lambda which destructures its input as MATCH-FORM and executes BODY.
+
+Note that you have to enclose the MATCH-FORM in a pair of parens,
+such that:
+
+ (-lambda (x) body)
+ (-lambda (x y ...) body)
+
+has the usual semantics of `lambda'. Furthermore, these get
+translated into normal lambda, so there is no performance
+penalty.
+
+See `-let' for the description of destructuring mechanism."
+ (declare (doc-string 2) (indent defun)
+ (debug (&define sexp
+ [&optional stringp]
+ [&optional ("interactive" interactive)]
+ def-body)))
+ (cond
+ ((not (consp match-form))
+ (signal 'wrong-type-argument "match-form must be a list"))
+ ;; no destructuring, so just return regular lambda to make things faster
+ ((-all? 'symbolp match-form)
+ `(lambda ,match-form ,@body))
+ (t
+ (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form)))
+ ;; TODO: because inputs to the lambda are evaluated only once,
+ ;; -let* need not to create the extra bindings to ensure that.
+ ;; We should find a way to optimize that. Not critical however.
+ `(lambda ,(--map (cadr it) inputs)
+ (-let* ,inputs ,@body))))))
+
+(defmacro -setq (&rest forms)
+ "Bind each MATCH-FORM to the value of its VAL.
+
+MATCH-FORM destructuring is done according to the rules of `-let'.
+
+This macro allows you to bind multiple variables by destructuring
+the value, so for example:
+
+ (-setq (a b) x
+ (&plist :c c) plist)
+
+expands roughly speaking to the following code
+
+ (setq a (car x)
+ b (cadr x)
+ c (plist-get plist :c))
+
+Care is taken to only evaluate each VAL once so that in case of
+multiple assignments it does not cause unexpected side effects.
+
+\(fn [MATCH-FORM VAL]...)"
+ (declare (debug (&rest sexp form))
+ (indent 1))
+ (when (= (mod (length forms) 2) 1)
+ (error "Odd number of arguments"))
+ (let* ((forms-and-sources
+ ;; First get all the necessary mappings with all the
+ ;; intermediate bindings.
+ (-map (lambda (x) (dash--match (car x) (cadr x)))
+ (-partition 2 forms)))
+ ;; To preserve the logic of dynamic scoping we must ensure
+ ;; that we `setq' the variables outside of the `let*' form
+ ;; which holds the destructured intermediate values. For
+ ;; this we generate for each variable a placeholder which is
+ ;; bound to (lexically) the result of the destructuring.
+ ;; Then outside of the helper `let*' form we bind all the
+ ;; original variables to their respective placeholders.
+ ;; TODO: There is a lot of room for possible optimization,
+ ;; for start playing with `special-variable-p' to eliminate
+ ;; unnecessary re-binding.
+ (variables-to-placeholders
+ (-mapcat
+ (lambda (bindings)
+ (-map
+ (lambda (binding)
+ (let ((var (car binding)))
+ (list var (make-symbol (concat "--dash-binding-" (symbol-name var) "--")))))
+ (--filter (not (string-prefix-p "--" (symbol-name (car it)))) bindings)))
+ forms-and-sources)))
+ `(let ,(-map 'cadr variables-to-placeholders)
+ (let* ,(-flatten-n 1 forms-and-sources)
+ (setq ,@(-flatten (-map 'reverse variables-to-placeholders))))
+ (setq ,@(-flatten variables-to-placeholders)))))
+
+(defmacro -if-let* (vars-vals then &rest else)
+ "If all VALS evaluate to true, bind them to their corresponding
+VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list
+of (VAR VAL) pairs.
+
+Note: binding is done according to `-let*'. VALS are evaluated
+sequentially, and evaluation stops after the first nil VAL is
+encountered."
+ (declare (debug ((&rest (sexp form)) form body))
+ (indent 2))
+ (->> vars-vals
+ (--mapcat (dash--match (car it) (cadr it)))
+ (--reduce-r-from
+ (let ((var (car it))
+ (val (cadr it)))
+ `(let ((,var ,val))
+ (if ,var ,acc ,@else)))
+ then)))
+
+(defmacro -if-let (var-val then &rest else)
+ "If VAL evaluates to non-nil, bind it to VAR and do THEN,
+otherwise do ELSE.
+
+Note: binding is done according to `-let'.
+
+\(fn (VAR VAL) THEN &rest ELSE)"
+ (declare (debug ((sexp form) form body))
+ (indent 2))
+ `(-if-let* (,var-val) ,then ,@else))
+
+(defmacro --if-let (val then &rest else)
+ "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN,
+otherwise do ELSE."
+ (declare (debug (form form body))
+ (indent 2))
+ `(-if-let (it ,val) ,then ,@else))
+
+(defmacro -when-let* (vars-vals &rest body)
+ "If all VALS evaluate to true, bind them to their corresponding
+VARS and execute body. VARS-VALS should be a list of (VAR VAL)
+pairs.
+
+Note: binding is done according to `-let*'. VALS are evaluated
+sequentially, and evaluation stops after the first nil VAL is
+encountered."
+ (declare (debug ((&rest (sexp form)) body))
+ (indent 1))
+ `(-if-let* ,vars-vals (progn ,@body)))
+
+(defmacro -when-let (var-val &rest body)
+ "If VAL evaluates to non-nil, bind it to VAR and execute body.
+
+Note: binding is done according to `-let'.
+
+\(fn (VAR VAL) &rest BODY)"
+ (declare (debug ((sexp form) body))
+ (indent 1))
+ `(-if-let ,var-val (progn ,@body)))
+
+(defmacro --when-let (val &rest body)
+ "If VAL evaluates to non-nil, bind it to symbol `it' and
+execute body."
+ (declare (debug (form body))
+ (indent 1))
+ `(--if-let ,val (progn ,@body)))
+
+(defvar -compare-fn nil
+ "Tests for equality use this function or `equal' if this is nil.
+It should only be set using dynamic scope with a let, like:
+
+ (let ((-compare-fn #\\='=)) (-union numbers1 numbers2 numbers3)")
+
+(defun -distinct (list)
+ "Return a new list with all duplicates removed.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil.
+
+Alias: `-uniq'"
+ ;; Implementation note: The speedup gained from hash table lookup
+ ;; starts to outweigh its overhead for lists of length greater than
+ ;; 32. See discussion in PR #305.
+ (let* ((len (length list))
+ (lut (and (> len 32)
+ ;; Check that `-compare-fn' is a valid hash-table
+ ;; lookup function or `nil'.
+ (memq -compare-fn '(nil equal eq eql))
+ (make-hash-table :test (or -compare-fn #'equal)
+ :size len))))
+ (if lut
+ (--filter (unless (gethash it lut)
+ (puthash it t lut))
+ list)
+ (--each list (unless (-contains? lut it) (!cons it lut)))
+ (nreverse lut))))
+
+(defalias '-uniq '-distinct)
+
+(defun -union (list list2)
+ "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil."
+ ;; We fall back to iteration implementation if the comparison
+ ;; function isn't one of `eq', `eql' or `equal'.
+ (let* ((result (reverse list))
+ ;; TODO: get rid of this dynamic variable, pass it as an
+ ;; argument instead.
+ (-compare-fn (if (bound-and-true-p -compare-fn)
+ -compare-fn
+ 'equal)))
+ (if (memq -compare-fn '(eq eql equal))
+ (let ((ht (make-hash-table :test -compare-fn)))
+ (--each list (puthash it t ht))
+ (--each list2 (unless (gethash it ht) (!cons it result))))
+ (--each list2 (unless (-contains? result it) (!cons it result))))
+ (nreverse result)))
+
+(defun -intersection (list list2)
+ "Return a new list containing only the elements that are members of both LIST and LIST2.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil."
+ (--filter (-contains? list2 it) list))
+
+(defun -difference (list list2)
+ "Return a new list with only the members of LIST that are not in LIST2.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil."
+ (--filter (not (-contains? list2 it)) list))
+
+(defun -powerset (list)
+ "Return the power set of LIST."
+ (if (null list) '(())
+ (let ((last (-powerset (cdr list))))
+ (append (mapcar (lambda (x) (cons (car list) x)) last)
+ last))))
+
+(defun -permutations (list)
+ "Return the permutations of LIST."
+ (if (null list) '(())
+ (apply #'append
+ (mapcar (lambda (x)
+ (mapcar (lambda (perm) (cons x perm))
+ (-permutations (remove x list))))
+ list))))
+
+(defun -inits (list)
+ "Return all prefixes of LIST."
+ (let ((res (list list)))
+ (setq list (reverse list))
+ (while list
+ (push (reverse (!cdr list)) res))
+ res))
+
+(defun -tails (list)
+ "Return all suffixes of LIST"
+ (-reductions-r-from 'cons nil list))
+
+(defun -common-prefix (&rest lists)
+ "Return the longest common prefix of LISTS."
+ (declare (pure t) (side-effect-free t))
+ (--reduce (--take-while (and acc (equal (pop acc) it)) it)
+ lists))
+
+(defun -common-suffix (&rest lists)
+ "Return the longest common suffix of LISTS."
+ (nreverse (apply #'-common-prefix (mapcar #'reverse lists))))
+
+(defun -contains? (list element)
+ "Return non-nil if LIST contains ELEMENT.
+
+The test for equality is done with `equal', or with `-compare-fn'
+if that's non-nil.
+
+Alias: `-contains-p'"
+ (not
+ (null
+ (cond
+ ((null -compare-fn) (member element list))
+ ((eq -compare-fn 'eq) (memq element list))
+ ((eq -compare-fn 'eql) (memql element list))
+ (t
+ (let ((lst list))
+ (while (and lst
+ (not (funcall -compare-fn element (car lst))))
+ (setq lst (cdr lst)))
+ lst))))))
+
+(defalias '-contains-p '-contains?)
+
+(defun -same-items? (list list2)
+ "Return true if LIST and LIST2 has the same items.
+
+The order of the elements in the lists does not matter.
+
+Alias: `-same-items-p'"
+ (let ((length-a (length list))
+ (length-b (length list2)))
+ (and
+ (= length-a length-b)
+ (= length-a (length (-intersection list list2))))))
+
+(defalias '-same-items-p '-same-items?)
+
+(defun -is-prefix? (prefix list)
+ "Return non-nil if PREFIX is prefix of LIST.
+
+Alias: `-is-prefix-p'"
+ (declare (pure t) (side-effect-free t))
+ (--each-while list (equal (car prefix) it)
+ (!cdr prefix))
+ (not prefix))
+
+(defun -is-suffix? (suffix list)
+ "Return non-nil if SUFFIX is suffix of LIST.
+
+Alias: `-is-suffix-p'"
+ (declare (pure t) (side-effect-free t))
+ (-is-prefix? (reverse suffix) (reverse list)))
+
+(defun -is-infix? (infix list)
+ "Return non-nil if INFIX is infix of LIST.
+
+This operation runs in O(n^2) time
+
+Alias: `-is-infix-p'"
+ (declare (pure t) (side-effect-free t))
+ (let (done)
+ (while (and (not done) list)
+ (setq done (-is-prefix? infix list))
+ (!cdr list))
+ done))
+
+(defalias '-is-prefix-p '-is-prefix?)
+(defalias '-is-suffix-p '-is-suffix?)
+(defalias '-is-infix-p '-is-infix?)
+
+(defun -sort (comparator list)
+ "Sort LIST, stably, comparing elements using COMPARATOR.
+Return the sorted list. LIST is NOT modified by side effects.
+COMPARATOR is called with two elements of LIST, and should return non-nil
+if the first element should sort before the second."
+ (sort (copy-sequence list) comparator))
+
+(defmacro --sort (form list)
+ "Anaphoric form of `-sort'."
+ (declare (debug (form form)))
+ `(-sort (lambda (it other) ,form) ,list))
+
+(defun -list (&rest args)
+ "Return a list with ARGS.
+
+If first item of ARGS is already a list, simply return ARGS. If
+not, return a list with ARGS as elements."
+ (declare (pure t) (side-effect-free t))
+ (let ((arg (car args)))
+ (if (listp arg) arg args)))
+
+(defun -repeat (n x)
+ "Return a list with X repeated N times.
+Return nil if N is less than 1."
+ (declare (pure t) (side-effect-free t))
+ (let (ret)
+ (--dotimes n (!cons x ret))
+ ret))
+
+(defun -sum (list)
+ "Return the sum of LIST."
+ (declare (pure t) (side-effect-free t))
+ (apply '+ list))
+
+(defun -running-sum (list)
+ "Return a list with running sums of items in LIST.
+
+LIST must be non-empty."
+ (declare (pure t) (side-effect-free t))
+ (unless (consp list)
+ (error "LIST must be non-empty"))
+ (-reductions '+ list))
+
+(defun -product (list)
+ "Return the product of LIST."
+ (declare (pure t) (side-effect-free t))
+ (apply '* list))
+
+(defun -running-product (list)
+ "Return a list with running products of items in LIST.
+
+LIST must be non-empty."
+ (declare (pure t) (side-effect-free t))
+ (unless (consp list)
+ (error "LIST must be non-empty"))
+ (-reductions '* list))
+
+(defun -max (list)
+ "Return the largest value from LIST of numbers or markers."
+ (declare (pure t) (side-effect-free t))
+ (apply 'max list))
+
+(defun -min (list)
+ "Return the smallest value from LIST of numbers or markers."
+ (declare (pure t) (side-effect-free t))
+ (apply 'min list))
+
+(defun -max-by (comparator list)
+ "Take a comparison function COMPARATOR and a LIST and return
+the greatest element of the list by the comparison function.
+
+See also combinator `-on' which can transform the values before
+comparing them."
+ (--reduce (if (funcall comparator it acc) it acc) list))
+
+(defun -min-by (comparator list)
+ "Take a comparison function COMPARATOR and a LIST and return
+the least element of the list by the comparison function.
+
+See also combinator `-on' which can transform the values before
+comparing them."
+ (--reduce (if (funcall comparator it acc) acc it) list))
+
+(defmacro --max-by (form list)
+ "Anaphoric version of `-max-by'.
+
+The items for the comparator form are exposed as \"it\" and \"other\"."
+ (declare (debug (form form)))
+ `(-max-by (lambda (it other) ,form) ,list))
+
+(defmacro --min-by (form list)
+ "Anaphoric version of `-min-by'.
+
+The items for the comparator form are exposed as \"it\" and \"other\"."
+ (declare (debug (form form)))
+ `(-min-by (lambda (it other) ,form) ,list))
+
+(defun -iterate (fun init n)
+ "Return a list of iterated applications of FUN to INIT.
+
+This means a list of form:
+
+ (init (fun init) (fun (fun init)) ...)
+
+N is the length of the returned list."
+ (if (= n 0) nil
+ (let ((r (list init)))
+ (--dotimes (1- n)
+ (push (funcall fun (car r)) r))
+ (nreverse r))))
+
+(defun -fix (fn list)
+ "Compute the (least) fixpoint of FN with initial input LIST.
+
+FN is called at least once, results are compared with `equal'."
+ (let ((re (funcall fn list)))
+ (while (not (equal list re))
+ (setq list re)
+ (setq re (funcall fn re)))
+ re))
+
+(defmacro --fix (form list)
+ "Anaphoric form of `-fix'."
+ `(-fix (lambda (it) ,form) ,list))
+
+(defun -unfold (fun seed)
+ "Build a list from SEED using FUN.
+
+This is \"dual\" operation to `-reduce-r': while -reduce-r
+consumes a list to produce a single value, `-unfold' takes a
+seed value and builds a (potentially infinite!) list.
+
+FUN should return `nil' to stop the generating process, or a
+cons (A . B), where A will be prepended to the result and B is
+the new seed."
+ (let ((last (funcall fun seed)) r)
+ (while last
+ (push (car last) r)
+ (setq last (funcall fun (cdr last))))
+ (nreverse r)))
+
+(defmacro --unfold (form seed)
+ "Anaphoric version of `-unfold'."
+ (declare (debug (form form)))
+ `(-unfold (lambda (it) ,form) ,seed))
+
+(defun -cons-pair? (con)
+ "Return non-nil if CON is true cons pair.
+That is (A . B) where B is not a list.
+
+Alias: `-cons-pair-p'"
+ (declare (pure t) (side-effect-free t))
+ (and (listp con)
+ (not (listp (cdr con)))))
+
+(defalias '-cons-pair-p '-cons-pair?)
+
+(defun -cons-to-list (con)
+ "Convert a cons pair to a list with `car' and `cdr' of the pair respectively."
+ (declare (pure t) (side-effect-free t))
+ (list (car con) (cdr con)))
+
+(defun -value-to-list (val)
+ "Convert a value to a list.
+
+If the value is a cons pair, make a list with two elements, `car'
+and `cdr' of the pair respectively.
+
+If the value is anything else, wrap it in a list."
+ (declare (pure t) (side-effect-free t))
+ (cond
+ ((-cons-pair? val) (-cons-to-list val))
+ (t (list val))))
+
+(defun -tree-mapreduce-from (fn folder init-value tree)
+ "Apply FN to each element of TREE, and make a list of the results.
+If elements of TREE are lists themselves, apply FN recursively to
+elements of these nested lists.
+
+Then reduce the resulting lists using FOLDER and initial value
+INIT-VALUE. See `-reduce-r-from'.
+
+This is the same as calling `-tree-reduce-from' after `-tree-map'
+but is twice as fast as it only traverse the structure once."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) (funcall fn tree))
+ ((listp tree)
+ (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree)))
+ (t (funcall fn tree))))
+
+(defmacro --tree-mapreduce-from (form folder init-value tree)
+ "Anaphoric form of `-tree-mapreduce-from'."
+ (declare (debug (form form form form)))
+ `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree))
+
+(defun -tree-mapreduce (fn folder tree)
+ "Apply FN to each element of TREE, and make a list of the results.
+If elements of TREE are lists themselves, apply FN recursively to
+elements of these nested lists.
+
+Then reduce the resulting lists using FOLDER and initial value
+INIT-VALUE. See `-reduce-r-from'.
+
+This is the same as calling `-tree-reduce' after `-tree-map'
+but is twice as fast as it only traverse the structure once."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) (funcall fn tree))
+ ((listp tree)
+ (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree)))
+ (t (funcall fn tree))))
+
+(defmacro --tree-mapreduce (form folder tree)
+ "Anaphoric form of `-tree-mapreduce'."
+ (declare (debug (form form form)))
+ `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree))
+
+(defun -tree-map (fn tree)
+ "Apply FN to each element of TREE while preserving the tree structure."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) (funcall fn tree))
+ ((listp tree)
+ (mapcar (lambda (x) (-tree-map fn x)) tree))
+ (t (funcall fn tree))))
+
+(defmacro --tree-map (form tree)
+ "Anaphoric form of `-tree-map'."
+ (declare (debug (form form)))
+ `(-tree-map (lambda (it) ,form) ,tree))
+
+(defun -tree-reduce-from (fn init-value tree)
+ "Use FN to reduce elements of list TREE.
+If elements of TREE are lists themselves, apply the reduction recursively.
+
+FN is first applied to INIT-VALUE and first element of the list,
+then on this result and second element from the list etc.
+
+The initial value is ignored on cons pairs as they always contain
+two elements."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) tree)
+ ((listp tree)
+ (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree)))
+ (t tree)))
+
+(defmacro --tree-reduce-from (form init-value tree)
+ "Anaphoric form of `-tree-reduce-from'."
+ (declare (debug (form form form)))
+ `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree))
+
+(defun -tree-reduce (fn tree)
+ "Use FN to reduce elements of list TREE.
+If elements of TREE are lists themselves, apply the reduction recursively.
+
+FN is first applied to first element of the list and second
+element, then on this result and third element from the list etc.
+
+See `-reduce-r' for how exactly are lists of zero or one element handled."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) tree)
+ ((listp tree)
+ (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree)))
+ (t tree)))
+
+(defmacro --tree-reduce (form tree)
+ "Anaphoric form of `-tree-reduce'."
+ (declare (debug (form form)))
+ `(-tree-reduce (lambda (it acc) ,form) ,tree))
+
+(defun -tree-map-nodes (pred fun tree)
+ "Call FUN on each node of TREE that satisfies PRED.
+
+If PRED returns nil, continue descending down this node. If PRED
+returns non-nil, apply FUN to this node and do not descend
+further."
+ (if (funcall pred tree)
+ (funcall fun tree)
+ (if (and (listp tree)
+ (not (-cons-pair? tree)))
+ (-map (lambda (x) (-tree-map-nodes pred fun x)) tree)
+ tree)))
+
+(defmacro --tree-map-nodes (pred form tree)
+ "Anaphoric form of `-tree-map-nodes'."
+ `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree))
+
+(defun -tree-seq (branch children tree)
+ "Return a sequence of the nodes in TREE, in depth-first search order.
+
+BRANCH is a predicate of one argument that returns non-nil if the
+passed argument is a branch, that is, a node that can have children.
+
+CHILDREN is a function of one argument that returns the children
+of the passed branch node.
+
+Non-branch nodes are simply copied."
+ (cons tree
+ (when (funcall branch tree)
+ (-mapcat (lambda (x) (-tree-seq branch children x))
+ (funcall children tree)))))
+
+(defmacro --tree-seq (branch children tree)
+ "Anaphoric form of `-tree-seq'."
+ `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree))
+
+(defun -clone (list)
+ "Create a deep copy of LIST.
+The new list has the same elements and structure but all cons are
+replaced with new ones. This is useful when you need to clone a
+structure such as plist or alist."
+ (declare (pure t) (side-effect-free t))
+ (-tree-map 'identity list))
+
+;;; Font lock
+
+(defvar dash--keywords
+ `(;; TODO: Do not fontify the following automatic variables
+ ;; globally; detect and limit to their local anaphoric scope.
+ (,(concat "\\_<" (regexp-opt '("acc" "it" "it-index" "other")) "\\_>")
+ 0 font-lock-variable-name-face)
+ ;; Elisp macro fontification was static prior to Emacs 25.
+ ,@(when (< emacs-major-version 25)
+ (let ((macs '("!cdr"
+ "!cons"
+ "-->"
+ "--all?"
+ "--annotate"
+ "--any?"
+ "--count"
+ "--dotimes"
+ "--doto"
+ "--drop-while"
+ "--each"
+ "--each-r"
+ "--each-r-while"
+ "--each-while"
+ "--filter"
+ "--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?"
+ "--only-some?"
+ "--partition-by"
+ "--partition-by-header"
+ "--reduce"
+ "--reduce-from"
+ "--reduce-r"
+ "--reduce-r-from"
+ "--remove"
+ "--remove-first"
+ "--remove-last"
+ "--separate"
+ "--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->"
+ "-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")
+ :group 'dash
+ :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'."
+ :group 'dash :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
+ :group 'dash)
+
+(defcustom dash-enable-fontlock nil
+ "If non-nil, fontify Dash macro calls and special variables."
+ :group 'dash
+ :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")
+
+(provide 'dash)
+;;; dash.el ends here
--- /dev/null
+This is dash.info, produced by makeinfo version 6.5 from dash.texi.
+
+This manual is for ‘dash.el’ version 2.12.1.
+
+ Copyright © 2012-2015 Magnar Sveen
+
+ This program is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <https://www.gnu.org/licenses/>.
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* Dash: (dash.info). A modern list library for GNU Emacs
+END-INFO-DIR-ENTRY
+
+\1f
+File: dash.info, Node: Top, Next: Installation, Up: (dir)
+
+dash
+****
+
+This manual is for ‘dash.el’ version 2.12.1.
+
+ Copyright © 2012-2015 Magnar Sveen
+
+ This program is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <https://www.gnu.org/licenses/>.
+
+* Menu:
+
+* Installation::
+* Functions::
+* Development::
+* Index::
+
+— The Detailed Node Listing —
+
+Installation
+
+* Using in a package::
+* Fontification of special variables::
+
+Functions
+
+* Maps::
+* Sublist selection::
+* List to list::
+* Reductions::
+* Unfolding::
+* Predicates::
+* Partitioning::
+* Indexing::
+* Set operations::
+* Other list operations::
+* Tree operations::
+* Threading macros::
+* Binding::
+* Side-effects::
+* Destructive operations::
+* Function combinators::
+
+Development
+
+* Contribute:: How to contribute
+* Changes:: List of significant changes by version
+* Contributors:: List of contributors
+
+\1f
+File: dash.info, Node: Installation, Next: Functions, Prev: Top, Up: Top
+
+1 Installation
+**************
+
+It’s available on GNU ELPA (https://elpa.gnu.org/) and MELPA
+(https://melpa.org/); use ‘M-x package-install’:
+
+‘M-x package-install <RET> dash’
+ Install the dash library.
+
+‘M-x package-install <RET> dash-functional’
+ Optional, if you want the function combinators.
+
+ Alternatively, you can just dump dash.el or dash-functional.el in
+your load path somewhere.
+
+* Menu:
+
+* Using in a package::
+* Fontification of special variables::
+
+\1f
+File: dash.info, Node: Using in a package, Next: Fontification of special variables, Up: Installation
+
+1.1 Using in a package
+======================
+
+Add this to the big comment block at the top:
+
+ ;; Package-Requires: ((dash "2.12.1"))
+
+To get function combinators:
+
+ ;; Package-Requires: ((dash "2.12.1") (dash-functional "1.2.0") (emacs "24"))
+
+\1f
+File: dash.info, Node: Fontification of special variables, Prev: Using in a package, Up: Installation
+
+1.2 Fontification of special variables
+======================================
+
+Font lock of special Dash variables (‘it’, ‘acc’, etc.) in Emacs Lisp
+buffers can optionally be enabled with the autoloaded minor mode
+‘dash-fontify-mode’. In older Emacs versions which do not dynamically
+detect macros, the minor mode also fontifies Dash macro calls.
+
+ 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)
+
+\1f
+File: dash.info, Node: Functions, Next: Development, Prev: Installation, Up: Top
+
+2 Functions
+***********
+
+This chapter contains reference documentation for the dash application
+programming interface (API). All functions and constructs in the library
+are prefixed with a dash (-).
+
+ There are also anaphoric versions of functions where that makes
+sense, prefixed with two dashes instead of one.
+
+ For instance, while ‘-map’ takes a function to map over the list, one
+can also use the anaphoric form with double dashes - which will then be
+executed with ‘it’ exposed as the list item. Here’s an example:
+
+ (-map (lambda (n) (* n n)) '(1 2 3 4)) ;; normal version
+
+ (--map (* it it) '(1 2 3 4)) ;; anaphoric version
+
+Of course, the original can also be written like
+
+ (defun square (n) (* n n))
+
+ (-map 'square '(1 2 3 4))
+
+which demonstrates the usefulness of both versions.
+
+* Menu:
+
+* Maps::
+* Sublist selection::
+* List to list::
+* Reductions::
+* Unfolding::
+* Predicates::
+* Partitioning::
+* Indexing::
+* Set operations::
+* Other list operations::
+* Tree operations::
+* Threading macros::
+* Binding::
+* Side-effects::
+* Destructive operations::
+* Function combinators::
+
+\1f
+File: dash.info, Node: Maps, Next: Sublist selection, Up: Functions
+
+2.1 Maps
+========
+
+Functions in this category take a transforming function, which is then
+applied sequentially to each or selected elements of the input list.
+The results are collected in order and returned as new list.
+
+ -- Function: -map (fn list)
+ Return a new list consisting of the result of applying FN to the
+ items in LIST.
+
+ (-map (lambda (num) (* num num)) '(1 2 3 4))
+ ⇒ '(1 4 9 16)
+ (-map 'square '(1 2 3 4))
+ ⇒ '(1 4 9 16)
+ (--map (* it it) '(1 2 3 4))
+ ⇒ '(1 4 9 16)
+
+ -- Function: -map-when (pred rep list)
+ Return a new list where the elements in LIST that do not match the
+ PRED function are unchanged, and where the elements in LIST that do
+ match the PRED function are mapped through the REP function.
+
+ Alias: ‘-replace-where’
+
+ See also: ‘-update-at’ (*note -update-at::)
+
+ (-map-when 'even? 'square '(1 2 3 4))
+ ⇒ '(1 4 3 16)
+ (--map-when (> it 2) (* it it) '(1 2 3 4))
+ ⇒ '(1 2 9 16)
+ (--map-when (= it 2) 17 '(1 2 3 4))
+ ⇒ '(1 17 3 4)
+
+ -- Function: -map-first (pred rep list)
+ Replace first item in LIST satisfying PRED with result of REP
+ called on this item.
+
+ See also: ‘-map-when’ (*note -map-when::), ‘-replace-first’ (*note
+ -replace-first::)
+
+ (-map-first 'even? 'square '(1 2 3 4))
+ ⇒ '(1 4 3 4)
+ (--map-first (> it 2) (* it it) '(1 2 3 4))
+ ⇒ '(1 2 9 4)
+ (--map-first (= it 2) 17 '(1 2 3 2))
+ ⇒ '(1 17 3 2)
+
+ -- Function: -map-last (pred rep list)
+ Replace last item in LIST satisfying PRED with result of REP called
+ on this item.
+
+ See also: ‘-map-when’ (*note -map-when::), ‘-replace-last’ (*note
+ -replace-last::)
+
+ (-map-last 'even? 'square '(1 2 3 4))
+ ⇒ '(1 2 3 16)
+ (--map-last (> it 2) (* it it) '(1 2 3 4))
+ ⇒ '(1 2 3 16)
+ (--map-last (= it 2) 17 '(1 2 3 2))
+ ⇒ '(1 2 3 17)
+
+ -- Function: -map-indexed (fn list)
+ Return a new list consisting of the result of (FN index item) for
+ each item in LIST.
+
+ In the anaphoric form ‘--map-indexed’, the index is exposed as
+ symbol ‘it-index’.
+
+ See also: ‘-each-indexed’ (*note -each-indexed::).
+
+ (-map-indexed (lambda (index item) (- item index)) '(1 2 3 4))
+ ⇒ '(1 1 1 1)
+ (--map-indexed (- it it-index) '(1 2 3 4))
+ ⇒ '(1 1 1 1)
+
+ -- Function: -annotate (fn list)
+ Return a list of cons cells where each cell is FN applied to each
+ element of LIST paired with the unmodified element of LIST.
+
+ (-annotate '1+ '(1 2 3))
+ ⇒ '((2 . 1) (3 . 2) (4 . 3))
+ (-annotate 'length '(("h" "e" "l" "l" "o") ("hello" "world")))
+ ⇒ '((5 "h" "e" "l" "l" "o") (2 "hello" "world"))
+ (--annotate (< 1 it) '(0 1 2 3))
+ ⇒ '((nil . 0) (nil . 1) (t . 2) (t . 3))
+
+ -- Function: -splice (pred fun list)
+ Splice lists generated by FUN in place of elements matching PRED in
+ LIST.
+
+ FUN takes the element matching PRED as input.
+
+ This function can be used as replacement for ‘,@’ in case you need
+ to splice several lists at marked positions (for example with
+ keywords).
+
+ See also: ‘-splice-list’ (*note -splice-list::), ‘-insert-at’
+ (*note -insert-at::)
+
+ (-splice 'even? (lambda (x) (list x x)) '(1 2 3 4))
+ ⇒ '(1 2 2 3 4 4)
+ (--splice 't (list it it) '(1 2 3 4))
+ ⇒ '(1 1 2 2 3 3 4 4)
+ (--splice (equal it :magic) '((list of) (magical) (code)) '((foo) (bar) :magic (baz)))
+ ⇒ '((foo) (bar) (list of) (magical) (code) (baz))
+
+ -- Function: -splice-list (pred new-list list)
+ Splice NEW-LIST in place of elements matching PRED in LIST.
+
+ See also: ‘-splice’ (*note -splice::), ‘-insert-at’ (*note
+ -insert-at::)
+
+ (-splice-list 'keywordp '(a b c) '(1 :foo 2))
+ ⇒ '(1 a b c 2)
+ (-splice-list 'keywordp nil '(1 :foo 2))
+ ⇒ '(1 2)
+ (--splice-list (keywordp it) '(a b c) '(1 :foo 2))
+ ⇒ '(1 a b c 2)
+
+ -- Function: -mapcat (fn list)
+ Return the concatenation of the result of mapping FN over LIST.
+ Thus function FN should return a list.
+
+ (-mapcat 'list '(1 2 3))
+ ⇒ '(1 2 3)
+ (-mapcat (lambda (item) (list 0 item)) '(1 2 3))
+ ⇒ '(0 1 0 2 0 3)
+ (--mapcat (list 0 it) '(1 2 3))
+ ⇒ '(0 1 0 2 0 3)
+
+ -- Function: -copy (arg)
+ Create a shallow copy of LIST.
+
+ (fn LIST)
+
+ (-copy '(1 2 3))
+ ⇒ '(1 2 3)
+ (let ((a '(1 2 3))) (eq a (-copy a)))
+ ⇒ nil
+
+\1f
+File: dash.info, Node: Sublist selection, Next: List to list, Prev: Maps, Up: Functions
+
+2.2 Sublist selection
+=====================
+
+Functions returning a sublist of the original list.
+
+ -- Function: -filter (pred list)
+ Return a new list of the items in LIST for which PRED returns a
+ non-nil value.
+
+ Alias: ‘-select’
+
+ See also: ‘-keep’ (*note -keep::), ‘-remove’ (*note -remove::).
+
+ (-filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4))
+ ⇒ '(2 4)
+ (-filter 'even? '(1 2 3 4))
+ ⇒ '(2 4)
+ (--filter (= 0 (% it 2)) '(1 2 3 4))
+ ⇒ '(2 4)
+
+ -- Function: -remove (pred list)
+ Return a new list of the items in LIST for which PRED returns nil.
+
+ Alias: ‘-reject’
+
+ See also: ‘-filter’ (*note -filter::).
+
+ (-remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4))
+ ⇒ '(1 3)
+ (-remove 'even? '(1 2 3 4))
+ ⇒ '(1 3)
+ (--remove (= 0 (% it 2)) '(1 2 3 4))
+ ⇒ '(1 3)
+
+ -- Function: -remove-first (pred list)
+ Return a new list with the first item matching PRED removed.
+
+ Alias: ‘-reject-first’
+
+ See also: ‘-remove’ (*note -remove::), ‘-map-first’ (*note
+ -map-first::)
+
+ (-remove-first 'even? '(1 3 5 4 7 8 10))
+ ⇒ '(1 3 5 7 8 10)
+ (-remove-first 'stringp '(1 2 "first" "second" "third"))
+ ⇒ '(1 2 "second" "third")
+ (--remove-first (> it 3) '(1 2 3 4 5 6 7 8 9 10))
+ ⇒ '(1 2 3 5 6 7 8 9 10)
+
+ -- Function: -remove-last (pred list)
+ Return a new list with the last item matching PRED removed.
+
+ Alias: ‘-reject-last’
+
+ See also: ‘-remove’ (*note -remove::), ‘-map-last’ (*note
+ -map-last::)
+
+ (-remove-last 'even? '(1 3 5 4 7 8 10 11))
+ ⇒ '(1 3 5 4 7 8 11)
+ (-remove-last 'stringp '(1 2 "last" "second" "third"))
+ ⇒ '(1 2 "last" "second")
+ (--remove-last (> it 3) '(1 2 3 4 5 6 7 8 9 10))
+ ⇒ '(1 2 3 4 5 6 7 8 9)
+
+ -- Function: -remove-item (item list)
+ Remove all occurrences of ITEM from LIST.
+
+ Comparison is done with ‘equal’.
+
+ (-remove-item 3 '(1 2 3 2 3 4 5 3))
+ ⇒ '(1 2 2 4 5)
+ (-remove-item 'foo '(foo bar baz foo))
+ ⇒ '(bar baz)
+ (-remove-item "bob" '("alice" "bob" "eve" "bob" "dave"))
+ ⇒ '("alice" "eve" "dave")
+
+ -- Function: -non-nil (list)
+ Return all non-nil elements of LIST.
+
+ (-non-nil '(1 nil 2 nil nil 3 4 nil 5 nil))
+ ⇒ '(1 2 3 4 5)
+
+ -- Function: -slice (list from &optional to step)
+ Return copy of LIST, starting from index FROM to index TO.
+
+ FROM or TO may be negative. These values are then interpreted
+ modulo the length of the list.
+
+ If STEP is a number, only each STEPth item in the resulting section
+ is returned. Defaults to 1.
+
+ (-slice '(1 2 3 4 5) 1)
+ ⇒ '(2 3 4 5)
+ (-slice '(1 2 3 4 5) 0 3)
+ ⇒ '(1 2 3)
+ (-slice '(1 2 3 4 5 6 7 8 9) 1 -1 2)
+ ⇒ '(2 4 6 8)
+
+ -- Function: -take (n list)
+ Return a 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))
+ ⇒ nil
+
+ -- 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 a copy of the tail of LIST without the first 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-last’ (*note -drop-last::)
+
+ (-drop 3 '(1 2 3 4 5))
+ ⇒ '(4 5)
+ (-drop 17 '(1 2 3 4 5))
+ ⇒ nil
+ (-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))
+ ⇒ nil
+ (-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.
+
+ See also: ‘-drop-while’ (*note -drop-while::)
+
+ (-take-while 'even? '(1 2 3 4))
+ ⇒ nil
+ (-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 a copy of the tail of
+ LIST starting from its first element for which PRED returns nil.
+
+ 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)
+
+\1f
+File: dash.info, Node: List to list, Next: Reductions, Prev: Sublist selection, Up: Functions
+
+2.3 List to list
+================
+
+Functions returning a modified copy of the input list.
+
+ -- Function: -keep (fn list)
+ Return a new list of the non-nil results of applying FN to the
+ items in LIST.
+
+ If you want to select the original items satisfying a predicate use
+ ‘-filter’ (*note -filter::).
+
+ (-keep 'cdr '((1 2 3) (4 5) (6)))
+ ⇒ '((2 3) (5))
+ (-keep (lambda (num) (when (> num 3) (* 10 num))) '(1 2 3 4 5 6))
+ ⇒ '(40 50 60)
+ (--keep (when (> it 3) (* 10 it)) '(1 2 3 4 5 6))
+ ⇒ '(40 50 60)
+
+ -- Function: -concat (&rest lists)
+ Return a new list with the concatenation of the elements in the
+ supplied LISTS.
+
+ (-concat '(1))
+ ⇒ '(1)
+ (-concat '(1) '(2))
+ ⇒ '(1 2)
+ (-concat '(1) '(2 3) '(4))
+ ⇒ '(1 2 3 4)
+
+ -- Function: -flatten (l)
+ Take a nested list L and return its contents as a single, flat
+ list.
+
+ Note that because ‘nil’ represents a list of zero elements (an
+ empty list), any mention of nil in L will disappear after
+ flattening. If you need to preserve nils, consider ‘-flatten-n’
+ (*note -flatten-n::) or map them to some unique symbol and then map
+ them back.
+
+ Conses of two atoms are considered "terminals", that is, they
+ aren’t flattened further.
+
+ See also: ‘-flatten-n’ (*note -flatten-n::)
+
+ (-flatten '((1)))
+ ⇒ '(1)
+ (-flatten '((1 (2 3) (((4 (5)))))))
+ ⇒ '(1 2 3 4 5)
+ (-flatten '(1 2 (3 . 4)))
+ ⇒ '(1 2 (3 . 4))
+
+ -- Function: -flatten-n (num list)
+ Flatten NUM levels of a nested LIST.
+
+ See also: ‘-flatten’ (*note -flatten::)
+
+ (-flatten-n 1 '((1 2) ((3 4) ((5 6)))))
+ ⇒ '(1 2 (3 4) ((5 6)))
+ (-flatten-n 2 '((1 2) ((3 4) ((5 6)))))
+ ⇒ '(1 2 3 4 (5 6))
+ (-flatten-n 3 '((1 2) ((3 4) ((5 6)))))
+ ⇒ '(1 2 3 4 5 6)
+
+ -- Function: -replace (old new list)
+ Replace all OLD items in LIST with NEW.
+
+ Elements are compared using ‘equal’.
+
+ See also: ‘-replace-at’ (*note -replace-at::)
+
+ (-replace 1 "1" '(1 2 3 4 3 2 1))
+ ⇒ '("1" 2 3 4 3 2 "1")
+ (-replace "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo"))
+ ⇒ '("a" "nice" "bar" "sentence" "about" "bar")
+ (-replace 1 2 nil)
+ ⇒ nil
+
+ -- Function: -replace-first (old new list)
+ Replace the first occurrence of OLD with NEW in LIST.
+
+ Elements are compared using ‘equal’.
+
+ See also: ‘-map-first’ (*note -map-first::)
+
+ (-replace-first 1 "1" '(1 2 3 4 3 2 1))
+ ⇒ '("1" 2 3 4 3 2 1)
+ (-replace-first "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo"))
+ ⇒ '("a" "nice" "bar" "sentence" "about" "foo")
+ (-replace-first 1 2 nil)
+ ⇒ nil
+
+ -- Function: -replace-last (old new list)
+ Replace the last occurrence of OLD with NEW in LIST.
+
+ Elements are compared using ‘equal’.
+
+ See also: ‘-map-last’ (*note -map-last::)
+
+ (-replace-last 1 "1" '(1 2 3 4 3 2 1))
+ ⇒ '(1 2 3 4 3 2 "1")
+ (-replace-last "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo"))
+ ⇒ '("a" "nice" "foo" "sentence" "about" "bar")
+ (-replace-last 1 2 nil)
+ ⇒ nil
+
+ -- Function: -insert-at (n x list)
+ Return a list with X inserted into LIST at position N.
+
+ See also: ‘-splice’ (*note -splice::), ‘-splice-list’ (*note
+ -splice-list::)
+
+ (-insert-at 1 'x '(a b c))
+ ⇒ '(a x b c)
+ (-insert-at 12 'x '(a b c))
+ ⇒ '(a b c x)
+
+ -- Function: -replace-at (n x list)
+ Return a list with element at Nth position in LIST replaced with X.
+
+ See also: ‘-replace’ (*note -replace::)
+
+ (-replace-at 0 9 '(0 1 2 3 4 5))
+ ⇒ '(9 1 2 3 4 5)
+ (-replace-at 1 9 '(0 1 2 3 4 5))
+ ⇒ '(0 9 2 3 4 5)
+ (-replace-at 4 9 '(0 1 2 3 4 5))
+ ⇒ '(0 1 2 3 9 5)
+
+ -- Function: -update-at (n func list)
+ Return a list with element at Nth position in LIST replaced with
+ ‘(func (nth n list))‘.
+
+ See also: ‘-map-when’ (*note -map-when::)
+
+ (-update-at 0 (lambda (x) (+ x 9)) '(0 1 2 3 4 5))
+ ⇒ '(9 1 2 3 4 5)
+ (-update-at 1 (lambda (x) (+ x 8)) '(0 1 2 3 4 5))
+ ⇒ '(0 9 2 3 4 5)
+ (--update-at 2 (length it) '("foo" "bar" "baz" "quux"))
+ ⇒ '("foo" "bar" 3 "quux")
+
+ -- Function: -remove-at (n list)
+ Return a list with element at Nth position in LIST removed.
+
+ See also: ‘-remove-at-indices’ (*note -remove-at-indices::),
+ ‘-remove’ (*note -remove::)
+
+ (-remove-at 0 '("0" "1" "2" "3" "4" "5"))
+ ⇒ '("1" "2" "3" "4" "5")
+ (-remove-at 1 '("0" "1" "2" "3" "4" "5"))
+ ⇒ '("0" "2" "3" "4" "5")
+ (-remove-at 2 '("0" "1" "2" "3" "4" "5"))
+ ⇒ '("0" "1" "3" "4" "5")
+
+ -- Function: -remove-at-indices (indices list)
+ Return a list whose elements are elements from LIST without
+ elements selected as ‘(nth i list)‘ for all i from INDICES.
+
+ See also: ‘-remove-at’ (*note -remove-at::), ‘-remove’ (*note
+ -remove::)
+
+ (-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5"))
+ ⇒ '("1" "2" "3" "4" "5")
+ (-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5"))
+ ⇒ '("1" "3" "5")
+ (-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5"))
+ ⇒ '("1" "2" "3" "4")
+
+\1f
+File: dash.info, Node: Reductions, Next: Unfolding, Prev: List to list, Up: Functions
+
+2.4 Reductions
+==============
+
+Functions reducing lists into single value.
+
+ -- Function: -reduce-from (fn initial-value list)
+ Return the result of applying FN to INITIAL-VALUE and the first
+ item in LIST, then applying FN to that result and the 2nd item,
+ etc. If LIST contains no items, return INITIAL-VALUE and do not
+ call FN.
+
+ In the anaphoric form ‘--reduce-from’, the accumulated value is
+ exposed as symbol ‘acc’.
+
+ See also: ‘-reduce’ (*note -reduce::), ‘-reduce-r’ (*note
+ -reduce-r::)
+
+ (-reduce-from '- 10 '(1 2 3))
+ ⇒ 4
+ (-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "10" '(1 2 3))
+ ⇒ "(((10 - 1) - 2) - 3)"
+ (--reduce-from (concat acc " " it) "START" '("a" "b" "c"))
+ ⇒ "START a b c"
+
+ -- Function: -reduce-r-from (fn initial-value list)
+ Replace conses with FN, nil with INITIAL-VALUE and evaluate the
+ resulting expression. If LIST is empty, INITIAL-VALUE is returned
+ and FN is not called.
+
+ Note: this function works the same as ‘-reduce-from’ (*note
+ -reduce-from::) but the operation associates from right instead of
+ from left.
+
+ See also: ‘-reduce-r’ (*note -reduce-r::), ‘-reduce’ (*note
+ -reduce::)
+
+ (-reduce-r-from '- 10 '(1 2 3))
+ ⇒ -8
+ (-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "10" '(1 2 3))
+ ⇒ "(1 - (2 - (3 - 10)))"
+ (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c"))
+ ⇒ "a b c END"
+
+ -- Function: -reduce (fn list)
+ Return the result of applying FN to the first 2 items in LIST, then
+ applying FN to that result and the 3rd item, etc. If LIST contains
+ no items, return the result of calling FN with no arguments. If
+ LIST contains a single item, return that item and do not call FN.
+
+ In the anaphoric form ‘--reduce’, the accumulated value is exposed
+ as symbol ‘acc’.
+
+ See also: ‘-reduce-from’ (*note -reduce-from::), ‘-reduce-r’ (*note
+ -reduce-r::)
+
+ (-reduce '- '(1 2 3 4))
+ ⇒ -8
+ (-reduce 'list '(1 2 3 4))
+ ⇒ '(((1 2) 3) 4)
+ (--reduce (format "%s-%d" acc it) '(1 2 3))
+ ⇒ "1-2-3"
+
+ -- Function: -reduce-r (fn list)
+ Replace conses with FN and evaluate the resulting expression. The
+ final nil is ignored. If LIST contains no items, return the result
+ of calling FN with no arguments. If LIST contains a single item,
+ return that item and do not call FN.
+
+ The first argument of FN is the new item, the second is the
+ accumulated value.
+
+ Note: this function works the same as ‘-reduce’ (*note -reduce::)
+ but the operation associates from right instead of from left.
+
+ See also: ‘-reduce-r-from’ (*note -reduce-r-from::), ‘-reduce’
+ (*note -reduce::)
+
+ (-reduce-r '- '(1 2 3 4))
+ ⇒ -2
+ (-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3))
+ ⇒ "3-2-1"
+ (--reduce-r (format "%s-%d" acc it) '(1 2 3))
+ ⇒ "3-2-1"
+
+ -- Function: -reductions-from (fn init list)
+ Return a list of the intermediate values of the reduction.
+
+ See ‘-reduce-from’ (*note -reduce-from::) for explanation of the
+ arguments.
+
+ See also: ‘-reductions’ (*note -reductions::), ‘-reductions-r’
+ (*note -reductions-r::), ‘-reduce-r’ (*note -reduce-r::)
+
+ (-reductions-from (lambda (a i) (format "(%s FN %d)" a i)) "INIT" '(1 2 3 4))
+ ⇒ '("INIT" "(INIT FN 1)" "((INIT FN 1) FN 2)" "(((INIT FN 1) FN 2) FN 3)" "((((INIT FN 1) FN 2) FN 3) FN 4)")
+ (-reductions-from 'max 0 '(2 1 4 3))
+ ⇒ '(0 2 2 4 4)
+ (-reductions-from '* 1 '(1 2 3 4))
+ ⇒ '(1 1 2 6 24)
+
+ -- Function: -reductions-r-from (fn init list)
+ Return a list of the intermediate values of the reduction.
+
+ See ‘-reduce-r-from’ (*note -reduce-r-from::) for explanation of
+ the arguments.
+
+ See also: ‘-reductions-r’ (*note -reductions-r::), ‘-reductions’
+ (*note -reductions::), ‘-reduce’ (*note -reduce::)
+
+ (-reductions-r-from (lambda (i a) (format "(%d FN %s)" i a)) "INIT" '(1 2 3 4))
+ ⇒ '("(1 FN (2 FN (3 FN (4 FN INIT))))" "(2 FN (3 FN (4 FN INIT)))" "(3 FN (4 FN INIT))" "(4 FN INIT)" "INIT")
+ (-reductions-r-from 'max 0 '(2 1 4 3))
+ ⇒ '(4 4 4 3 0)
+ (-reductions-r-from '* 1 '(1 2 3 4))
+ ⇒ '(24 24 12 4 1)
+
+ -- Function: -reductions (fn list)
+ Return a list of the intermediate values of the reduction.
+
+ See ‘-reduce’ (*note -reduce::) for explanation of the arguments.
+
+ See also: ‘-reductions-from’ (*note -reductions-from::),
+ ‘-reductions-r’ (*note -reductions-r::), ‘-reduce-r’ (*note
+ -reduce-r::)
+
+ (-reductions (lambda (a i) (format "(%s FN %d)" a i)) '(1 2 3 4))
+ ⇒ '(1 "(1 FN 2)" "((1 FN 2) FN 3)" "(((1 FN 2) FN 3) FN 4)")
+ (-reductions '+ '(1 2 3 4))
+ ⇒ '(1 3 6 10)
+ (-reductions '* '(1 2 3 4))
+ ⇒ '(1 2 6 24)
+
+ -- Function: -reductions-r (fn list)
+ Return a list of the intermediate values of the reduction.
+
+ See ‘-reduce-r’ (*note -reduce-r::) for explanation of the
+ arguments.
+
+ See also: ‘-reductions-r-from’ (*note -reductions-r-from::),
+ ‘-reductions’ (*note -reductions::), ‘-reduce’ (*note -reduce::)
+
+ (-reductions-r (lambda (i a) (format "(%d FN %s)" i a)) '(1 2 3 4))
+ ⇒ '("(1 FN (2 FN (3 FN 4)))" "(2 FN (3 FN 4))" "(3 FN 4)" 4)
+ (-reductions-r '+ '(1 2 3 4))
+ ⇒ '(10 9 7 4)
+ (-reductions-r '* '(1 2 3 4))
+ ⇒ '(24 24 12 4)
+
+ -- Function: -count (pred list)
+ Counts the number of items in LIST where (PRED item) is non-nil.
+
+ (-count 'even? '(1 2 3 4 5))
+ ⇒ 2
+ (--count (< it 4) '(1 2 3 4))
+ ⇒ 3
+
+ -- Function: -sum (list)
+ Return the sum of LIST.
+
+ (-sum '())
+ ⇒ 0
+ (-sum '(1))
+ ⇒ 1
+ (-sum '(1 2 3 4))
+ ⇒ 10
+
+ -- Function: -running-sum (list)
+ Return a list with running sums of items in LIST.
+
+ LIST must be non-empty.
+
+ (-running-sum '(1 2 3 4))
+ ⇒ '(1 3 6 10)
+ (-running-sum '(1))
+ ⇒ '(1)
+ (-running-sum '())
+ ⇒ error
+
+ -- Function: -product (list)
+ Return the product of LIST.
+
+ (-product '())
+ ⇒ 1
+ (-product '(1))
+ ⇒ 1
+ (-product '(1 2 3 4))
+ ⇒ 24
+
+ -- Function: -running-product (list)
+ Return a list with running products of items in LIST.
+
+ LIST must be non-empty.
+
+ (-running-product '(1 2 3 4))
+ ⇒ '(1 2 6 24)
+ (-running-product '(1))
+ ⇒ '(1)
+ (-running-product '())
+ ⇒ error
+
+ -- Function: -inits (list)
+ Return all prefixes of LIST.
+
+ (-inits '(1 2 3 4))
+ ⇒ '(nil (1) (1 2) (1 2 3) (1 2 3 4))
+ (-inits nil)
+ ⇒ '(nil)
+ (-inits '(1))
+ ⇒ '(nil (1))
+
+ -- Function: -tails (list)
+ Return all suffixes of LIST
+
+ (-tails '(1 2 3 4))
+ ⇒ '((1 2 3 4) (2 3 4) (3 4) (4) nil)
+ (-tails nil)
+ ⇒ '(nil)
+ (-tails '(1))
+ ⇒ '((1) nil)
+
+ -- Function: -common-prefix (&rest lists)
+ Return the longest common prefix of LISTS.
+
+ (-common-prefix '(1))
+ ⇒ '(1)
+ (-common-prefix '(1 2) '(3 4) '(1 2))
+ ⇒ nil
+ (-common-prefix '(1 2) '(1 2 3) '(1 2 3 4))
+ ⇒ '(1 2)
+
+ -- Function: -common-suffix (&rest lists)
+ Return the longest common suffix of LISTS.
+
+ (-common-suffix '(1))
+ ⇒ '(1)
+ (-common-suffix '(1 2) '(3 4) '(1 2))
+ ⇒ nil
+ (-common-suffix '(1 2 3 4) '(2 3 4) '(3 4))
+ ⇒ '(3 4)
+
+ -- Function: -min (list)
+ Return the smallest value from LIST of numbers or markers.
+
+ (-min '(0))
+ ⇒ 0
+ (-min '(3 2 1))
+ ⇒ 1
+ (-min '(1 2 3))
+ ⇒ 1
+
+ -- Function: -min-by (comparator list)
+ Take a comparison function COMPARATOR and a LIST and return the
+ least element of the list by the comparison function.
+
+ See also combinator ‘-on’ (*note -on::) which can transform the
+ values before comparing them.
+
+ (-min-by '> '(4 3 6 1))
+ ⇒ 1
+ (--min-by (> (car it) (car other)) '((1 2 3) (2) (3 2)))
+ ⇒ '(1 2 3)
+ (--min-by (> (length it) (length other)) '((1 2 3) (2) (3 2)))
+ ⇒ '(2)
+
+ -- Function: -max (list)
+ Return the largest value from LIST of numbers or markers.
+
+ (-max '(0))
+ ⇒ 0
+ (-max '(3 2 1))
+ ⇒ 3
+ (-max '(1 2 3))
+ ⇒ 3
+
+ -- Function: -max-by (comparator list)
+ Take a comparison function COMPARATOR and a LIST and return the
+ greatest element of the list by the comparison function.
+
+ See also combinator ‘-on’ (*note -on::) which can transform the
+ values before comparing them.
+
+ (-max-by '> '(4 3 6 1))
+ ⇒ 6
+ (--max-by (> (car it) (car other)) '((1 2 3) (2) (3 2)))
+ ⇒ '(3 2)
+ (--max-by (> (length it) (length other)) '((1 2 3) (2) (3 2)))
+ ⇒ '(1 2 3)
+
+\1f
+File: dash.info, Node: Unfolding, Next: Predicates, Prev: Reductions, Up: Functions
+
+2.5 Unfolding
+=============
+
+Operations dual to reductions, building lists from seed value rather
+than consuming a list to produce a single value.
+
+ -- Function: -iterate (fun init n)
+ Return a list of iterated applications of FUN to INIT.
+
+ This means a list of form:
+
+ (init (fun init) (fun (fun init)) ...)
+
+ N is the length of the returned list.
+
+ (-iterate '1+ 1 10)
+ ⇒ '(1 2 3 4 5 6 7 8 9 10)
+ (-iterate (lambda (x) (+ x x)) 2 5)
+ ⇒ '(2 4 8 16 32)
+ (--iterate (* it it) 2 5)
+ ⇒ '(2 4 16 256 65536)
+
+ -- Function: -unfold (fun seed)
+ Build a list from SEED using FUN.
+
+ This is "dual" operation to ‘-reduce-r’ (*note -reduce-r::): while
+ -reduce-r consumes a list to produce a single value, ‘-unfold’
+ (*note -unfold::) takes a seed value and builds a (potentially
+ infinite!) list.
+
+ FUN should return ‘nil’ to stop the generating process, or a cons
+ (A . B), where A will be prepended to the result and B is the new
+ seed.
+
+ (-unfold (lambda (x) (unless (= x 0) (cons x (1- x)))) 10)
+ ⇒ '(10 9 8 7 6 5 4 3 2 1)
+ (--unfold (when it (cons it (cdr it))) '(1 2 3 4))
+ ⇒ '((1 2 3 4) (2 3 4) (3 4) (4))
+ (--unfold (when it (cons it (butlast it))) '(1 2 3 4))
+ ⇒ '((1 2 3 4) (1 2 3) (1 2) (1))
+
+\1f
+File: dash.info, Node: Predicates, Next: Partitioning, Prev: Unfolding, Up: Functions
+
+2.6 Predicates
+==============
+
+ -- Function: -any? (pred list)
+ Return t if (PRED x) is non-nil for any x in LIST, else nil.
+
+ Alias: ‘-any-p’, ‘-some?’, ‘-some-p’
+
+ (-any? 'even? '(1 2 3))
+ ⇒ t
+ (-any? 'even? '(1 3 5))
+ ⇒ nil
+ (-any? 'null '(1 3 5))
+ ⇒ nil
+
+ -- Function: -all? (pred list)
+ Return t if (PRED x) is non-nil for all x in LIST, else nil.
+
+ Alias: ‘-all-p’, ‘-every?’, ‘-every-p’
+
+ (-all? 'even? '(1 2 3))
+ ⇒ nil
+ (-all? 'even? '(2 4 6))
+ ⇒ t
+ (--all? (= 0 (% it 2)) '(2 4 6))
+ ⇒ t
+
+ -- Function: -none? (pred list)
+ Return t if (PRED x) is nil for all x in LIST, else nil.
+
+ Alias: ‘-none-p’
+
+ (-none? 'even? '(1 2 3))
+ ⇒ nil
+ (-none? 'even? '(1 3 5))
+ ⇒ t
+ (--none? (= 0 (% it 2)) '(1 2 3))
+ ⇒ nil
+
+ -- Function: -only-some? (pred list)
+ Return ‘t‘ if at least one item of LIST matches PRED and at least
+ one item of LIST does not match PRED. Return ‘nil‘ both if all
+ items match the predicate or if none of the items match the
+ predicate.
+
+ Alias: ‘-only-some-p’
+
+ (-only-some? 'even? '(1 2 3))
+ ⇒ t
+ (-only-some? 'even? '(1 3 5))
+ ⇒ nil
+ (-only-some? 'even? '(2 4 6))
+ ⇒ nil
+
+ -- Function: -contains? (list element)
+ Return non-nil if LIST contains ELEMENT.
+
+ The test for equality is done with ‘equal’, or with ‘-compare-fn’
+ if that’s non-nil.
+
+ Alias: ‘-contains-p’
+
+ (-contains? '(1 2 3) 1)
+ ⇒ t
+ (-contains? '(1 2 3) 2)
+ ⇒ t
+ (-contains? '(1 2 3) 4)
+ ⇒ nil
+
+ -- Function: -same-items? (list list2)
+ Return true if LIST and LIST2 has the same items.
+
+ The order of the elements in the lists does not matter.
+
+ Alias: ‘-same-items-p’
+
+ (-same-items? '(1 2 3) '(1 2 3))
+ ⇒ t
+ (-same-items? '(1 2 3) '(3 2 1))
+ ⇒ t
+ (-same-items? '(1 2 3) '(1 2 3 4))
+ ⇒ nil
+
+ -- Function: -is-prefix? (prefix list)
+ Return non-nil if PREFIX is prefix of LIST.
+
+ Alias: ‘-is-prefix-p’
+
+ (-is-prefix? '(1 2 3) '(1 2 3 4 5))
+ ⇒ t
+ (-is-prefix? '(1 2 3 4 5) '(1 2 3))
+ ⇒ nil
+ (-is-prefix? '(1 3) '(1 2 3 4 5))
+ ⇒ nil
+
+ -- Function: -is-suffix? (suffix list)
+ Return non-nil if SUFFIX is suffix of LIST.
+
+ Alias: ‘-is-suffix-p’
+
+ (-is-suffix? '(3 4 5) '(1 2 3 4 5))
+ ⇒ t
+ (-is-suffix? '(1 2 3 4 5) '(3 4 5))
+ ⇒ nil
+ (-is-suffix? '(3 5) '(1 2 3 4 5))
+ ⇒ nil
+
+ -- Function: -is-infix? (infix list)
+ Return non-nil if INFIX is infix of LIST.
+
+ This operation runs in O(n^2) time
+
+ Alias: ‘-is-infix-p’
+
+ (-is-infix? '(1 2 3) '(1 2 3 4 5))
+ ⇒ t
+ (-is-infix? '(2 3 4) '(1 2 3 4 5))
+ ⇒ t
+ (-is-infix? '(3 4 5) '(1 2 3 4 5))
+ ⇒ t
+
+\1f
+File: dash.info, Node: Partitioning, Next: Indexing, Prev: Predicates, Up: Functions
+
+2.7 Partitioning
+================
+
+Functions partitioning the input list into a list of lists.
+
+ -- Function: -split-at (n list)
+ Return a list of ((-take N LIST) (-drop N LIST)), in no more than
+ one pass through the list.
+
+ (-split-at 3 '(1 2 3 4 5))
+ ⇒ '((1 2 3) (4 5))
+ (-split-at 17 '(1 2 3 4 5))
+ ⇒ '((1 2 3 4 5) nil)
+
+ -- Function: -split-with (pred list)
+ Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)),
+ in no more than one pass through the list.
+
+ (-split-with 'even? '(1 2 3 4))
+ ⇒ '(nil (1 2 3 4))
+ (-split-with 'even? '(2 4 5 6))
+ ⇒ '((2 4) (5 6))
+ (--split-with (< it 4) '(1 2 3 4 3 2 1))
+ ⇒ '((1 2 3) (4 3 2 1))
+
+ -- Macro: -split-on (item list)
+ Split the LIST each time ITEM is found.
+
+ Unlike ‘-partition-by’ (*note -partition-by::), the ITEM is
+ discarded from the results. Empty lists are also removed from the
+ result.
+
+ Comparison is done by ‘equal’.
+
+ See also ‘-split-when’ (*note -split-when::)
+
+ (-split-on '| '(Nil | Leaf a | Node [Tree a]))
+ ⇒ '((Nil) (Leaf a) (Node [Tree a]))
+ (-split-on ':endgroup '("a" "b" :endgroup "c" :endgroup "d" "e"))
+ ⇒ '(("a" "b") ("c") ("d" "e"))
+ (-split-on ':endgroup '("a" "b" :endgroup :endgroup "d" "e"))
+ ⇒ '(("a" "b") ("d" "e"))
+
+ -- Function: -split-when (fn list)
+ Split the LIST on each element where FN returns non-nil.
+
+ Unlike ‘-partition-by’ (*note -partition-by::), the "matched"
+ element is discarded from the results. Empty lists are also
+ removed from the result.
+
+ This function can be thought of as a generalization of
+ ‘split-string’.
+
+ (-split-when 'even? '(1 2 3 4 5 6))
+ ⇒ '((1) (3) (5))
+ (-split-when 'even? '(1 2 3 4 6 8 9))
+ ⇒ '((1) (3) (9))
+ (--split-when (memq it '(&optional &rest)) '(a b &optional c d &rest args))
+ ⇒ '((a b) (c d) (args))
+
+ -- Function: -separate (pred list)
+ Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one
+ pass through the list.
+
+ (-separate (lambda (num) (= 0 (% num 2))) '(1 2 3 4 5 6 7))
+ ⇒ '((2 4 6) (1 3 5 7))
+ (--separate (< it 5) '(3 7 5 9 3 2 1 4 6))
+ ⇒ '((3 3 2 1 4) (7 5 9 6))
+ (-separate 'cdr '((1 2) (1) (1 2 3) (4)))
+ ⇒ '(((1 2) (1 2 3)) ((1) (4)))
+
+ -- Function: -partition (n list)
+ Return a new list with the items in LIST grouped into N-sized
+ sublists. If there are not enough items to make the last group
+ N-sized, those items are discarded.
+
+ (-partition 2 '(1 2 3 4 5 6))
+ ⇒ '((1 2) (3 4) (5 6))
+ (-partition 2 '(1 2 3 4 5 6 7))
+ ⇒ '((1 2) (3 4) (5 6))
+ (-partition 3 '(1 2 3 4 5 6 7))
+ ⇒ '((1 2 3) (4 5 6))
+
+ -- Function: -partition-all (n list)
+ Return a new list with the items in LIST grouped into N-sized
+ sublists. The last group may contain less than N items.
+
+ (-partition-all 2 '(1 2 3 4 5 6))
+ ⇒ '((1 2) (3 4) (5 6))
+ (-partition-all 2 '(1 2 3 4 5 6 7))
+ ⇒ '((1 2) (3 4) (5 6) (7))
+ (-partition-all 3 '(1 2 3 4 5 6 7))
+ ⇒ '((1 2 3) (4 5 6) (7))
+
+ -- Function: -partition-in-steps (n step list)
+ Return a new list with the items in LIST grouped into N-sized
+ sublists at offsets STEP apart. If there are not enough items to
+ make the last group N-sized, those items are discarded.
+
+ (-partition-in-steps 2 1 '(1 2 3 4))
+ ⇒ '((1 2) (2 3) (3 4))
+ (-partition-in-steps 3 2 '(1 2 3 4))
+ ⇒ '((1 2 3))
+ (-partition-in-steps 3 2 '(1 2 3 4 5))
+ ⇒ '((1 2 3) (3 4 5))
+
+ -- Function: -partition-all-in-steps (n step list)
+ Return a new list with the items in LIST grouped into N-sized
+ sublists at offsets STEP apart. The last groups may contain less
+ than N items.
+
+ (-partition-all-in-steps 2 1 '(1 2 3 4))
+ ⇒ '((1 2) (2 3) (3 4) (4))
+ (-partition-all-in-steps 3 2 '(1 2 3 4))
+ ⇒ '((1 2 3) (3 4))
+ (-partition-all-in-steps 3 2 '(1 2 3 4 5))
+ ⇒ '((1 2 3) (3 4 5) (5))
+
+ -- Function: -partition-by (fn list)
+ Apply FN to each item in LIST, splitting it each time FN returns a
+ new value.
+
+ (-partition-by 'even? '())
+ ⇒ '()
+ (-partition-by 'even? '(1 1 2 2 2 3 4 6 8))
+ ⇒ '((1 1) (2 2 2) (3) (4 6 8))
+ (--partition-by (< it 3) '(1 2 3 4 3 2 1))
+ ⇒ '((1 2) (3 4 3) (2 1))
+
+ -- Function: -partition-by-header (fn list)
+ Apply FN to the first item in LIST. That is the header value.
+ Apply FN to each item in LIST, splitting it each time FN returns
+ the header value, but only after seeing at least one other value
+ (the body).
+
+ (--partition-by-header (= it 1) '(1 2 3 1 2 1 2 3 4))
+ ⇒ '((1 2 3) (1 2) (1 2 3 4))
+ (--partition-by-header (> it 0) '(1 2 0 1 0 1 2 3 0))
+ ⇒ '((1 2 0) (1 0) (1 2 3 0))
+ (-partition-by-header 'even? '(2 1 1 1 4 1 3 5 6 6 1))
+ ⇒ '((2 1 1 1) (4 1 3 5) (6 6 1))
+
+ -- Function: -partition-after-pred (pred list)
+ Partition directly after each time PRED is true on an element of
+ LIST.
+
+ (-partition-after-pred #'odd? '())
+ ⇒ '()
+ (-partition-after-pred #'odd? '(1))
+ ⇒ '((1))
+ (-partition-after-pred #'odd? '(0 1))
+ ⇒ '((0 1))
+
+ -- Function: -partition-before-pred (pred list)
+ Partition directly before each time PRED is true on an element of
+ LIST.
+
+ (-partition-before-pred #'odd? '())
+ ⇒ '()
+ (-partition-before-pred #'odd? '(1))
+ ⇒ '((1))
+ (-partition-before-pred #'odd? '(0 1))
+ ⇒ '((0) (1))
+
+ -- Function: -partition-before-item (item list)
+ Partition directly before each time ITEM appears in LIST.
+
+ (-partition-before-item 3 '())
+ ⇒ '()
+ (-partition-before-item 3 '(1))
+ ⇒ '((1))
+ (-partition-before-item 3 '(3))
+ ⇒ '((3))
+
+ -- Function: -partition-after-item (item list)
+ Partition directly after each time ITEM appears in LIST.
+
+ (-partition-after-item 3 '())
+ ⇒ '()
+ (-partition-after-item 3 '(1))
+ ⇒ '((1))
+ (-partition-after-item 3 '(3))
+ ⇒ '((3))
+
+ -- Function: -group-by (fn list)
+ Separate LIST into an alist whose keys are FN applied to the
+ elements of LIST. Keys are compared by ‘equal’.
+
+ (-group-by 'even? '())
+ ⇒ '()
+ (-group-by 'even? '(1 1 2 2 2 3 4 6 8))
+ ⇒ '((nil 1 1 3) (t 2 2 2 4 6 8))
+ (--group-by (car (split-string it "/")) '("a/b" "c/d" "a/e"))
+ ⇒ '(("a" "a/b" "a/e") ("c" "c/d"))
+
+\1f
+File: dash.info, Node: Indexing, Next: Set operations, Prev: Partitioning, Up: Functions
+
+2.8 Indexing
+============
+
+Return indices of elements based on predicates, sort elements by indices
+etc.
+
+ -- Function: -elem-index (elem list)
+ Return the index of the first element in the given LIST which is
+ equal to the query element ELEM, or nil if there is no such
+ element.
+
+ (-elem-index 2 '(6 7 8 2 3 4))
+ ⇒ 3
+ (-elem-index "bar" '("foo" "bar" "baz"))
+ ⇒ 1
+ (-elem-index '(1 2) '((3) (5 6) (1 2) nil))
+ ⇒ 2
+
+ -- Function: -elem-indices (elem list)
+ Return the indices of all elements in LIST equal to the query
+ element ELEM, in ascending order.
+
+ (-elem-indices 2 '(6 7 8 2 3 4 2 1))
+ ⇒ '(3 6)
+ (-elem-indices "bar" '("foo" "bar" "baz"))
+ ⇒ '(1)
+ (-elem-indices '(1 2) '((3) (1 2) (5 6) (1 2) nil))
+ ⇒ '(1 3)
+
+ -- Function: -find-index (pred list)
+ Take a predicate PRED and a LIST and return the index of the first
+ element in the list satisfying the predicate, or nil if there is no
+ such element.
+
+ See also ‘-first’ (*note -first::).
+
+ (-find-index 'even? '(2 4 1 6 3 3 5 8))
+ ⇒ 0
+ (--find-index (< 5 it) '(2 4 1 6 3 3 5 8))
+ ⇒ 3
+ (-find-index (-partial 'string-lessp "baz") '("bar" "foo" "baz"))
+ ⇒ 1
+
+ -- Function: -find-last-index (pred list)
+ Take a predicate PRED and a LIST and return the index of the last
+ element in the list satisfying the predicate, or nil if there is no
+ such element.
+
+ See also ‘-last’ (*note -last::).
+
+ (-find-last-index 'even? '(2 4 1 6 3 3 5 8))
+ ⇒ 7
+ (--find-last-index (< 5 it) '(2 7 1 6 3 8 5 2))
+ ⇒ 5
+ (-find-last-index (-partial 'string-lessp "baz") '("q" "foo" "baz"))
+ ⇒ 1
+
+ -- Function: -find-indices (pred list)
+ Return the indices of all elements in LIST satisfying the predicate
+ PRED, in ascending order.
+
+ (-find-indices 'even? '(2 4 1 6 3 3 5 8))
+ ⇒ '(0 1 3 7)
+ (--find-indices (< 5 it) '(2 4 1 6 3 3 5 8))
+ ⇒ '(3 7)
+ (-find-indices (-partial 'string-lessp "baz") '("bar" "foo" "baz"))
+ ⇒ '(1)
+
+ -- Function: -grade-up (comparator list)
+ Grade elements of LIST using COMPARATOR relation, yielding a
+ permutation vector such that applying this permutation to LIST
+ sorts it in ascending order.
+
+ (-grade-up '< '(3 1 4 2 1 3 3))
+ ⇒ '(1 4 3 0 5 6 2)
+ (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-up '< l) l))
+ ⇒ '(1 1 2 3 3 3 4)
+
+ -- Function: -grade-down (comparator list)
+ Grade elements of LIST using COMPARATOR relation, yielding a
+ permutation vector such that applying this permutation to LIST
+ sorts it in descending order.
+
+ (-grade-down '< '(3 1 4 2 1 3 3))
+ ⇒ '(2 0 5 6 3 1 4)
+ (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-down '< l) l))
+ ⇒ '(4 3 3 3 2 1 1)
+
+\1f
+File: dash.info, Node: Set operations, Next: Other list operations, Prev: Indexing, Up: Functions
+
+2.9 Set operations
+==================
+
+Operations pretending lists are sets.
+
+ -- Function: -union (list list2)
+ Return a new list containing the elements of LIST and elements of
+ LIST2 that are not in LIST. The test for equality is done with
+ ‘equal’, or with ‘-compare-fn’ if that’s non-nil.
+
+ (-union '(1 2 3) '(3 4 5))
+ ⇒ '(1 2 3 4 5)
+ (-union '(1 2 3 4) '())
+ ⇒ '(1 2 3 4)
+ (-union '(1 1 2 2) '(3 2 1))
+ ⇒ '(1 1 2 2 3)
+
+ -- Function: -difference (list list2)
+ Return a new list with only the members of LIST that are not in
+ LIST2. The test for equality is done with ‘equal’, or with
+ ‘-compare-fn’ if that’s non-nil.
+
+ (-difference '() '())
+ ⇒ '()
+ (-difference '(1 2 3) '(4 5 6))
+ ⇒ '(1 2 3)
+ (-difference '(1 2 3 4) '(3 4 5 6))
+ ⇒ '(1 2)
+
+ -- Function: -intersection (list list2)
+ Return a new list containing only the elements that are members of
+ both LIST and LIST2. The test for equality is done with ‘equal’,
+ or with ‘-compare-fn’ if that’s non-nil.
+
+ (-intersection '() '())
+ ⇒ '()
+ (-intersection '(1 2 3) '(4 5 6))
+ ⇒ '()
+ (-intersection '(1 2 3 4) '(3 4 5 6))
+ ⇒ '(3 4)
+
+ -- Function: -powerset (list)
+ Return the power set of LIST.
+
+ (-powerset '())
+ ⇒ '(nil)
+ (-powerset '(x y z))
+ ⇒ '((x y z) (x y) (x z) (x) (y z) (y) (z) nil)
+
+ -- Function: -permutations (list)
+ Return the permutations of LIST.
+
+ (-permutations '())
+ ⇒ '(nil)
+ (-permutations '(1 2))
+ ⇒ '((1 2) (2 1))
+ (-permutations '(a b c))
+ ⇒ '((a b c) (a c b) (b a c) (b c a) (c a b) (c b a))
+
+ -- Function: -distinct (list)
+ Return a new list with all duplicates removed. The test for
+ equality is done with ‘equal’, or with ‘-compare-fn’ if that’s
+ non-nil.
+
+ Alias: ‘-uniq’
+
+ (-distinct '())
+ ⇒ '()
+ (-distinct '(1 2 2 4))
+ ⇒ '(1 2 4)
+ (-distinct '(t t t))
+ ⇒ '(t)
+
+\1f
+File: dash.info, Node: Other list operations, Next: Tree operations, Prev: Set operations, Up: Functions
+
+2.10 Other list operations
+==========================
+
+Other list functions not fit to be classified elsewhere.
+
+ -- Function: -rotate (n list)
+ Rotate LIST N places to the right. With N negative, rotate to the
+ left. The time complexity is O(n).
+
+ (-rotate 3 '(1 2 3 4 5 6 7))
+ ⇒ '(5 6 7 1 2 3 4)
+ (-rotate -3 '(1 2 3 4 5 6 7))
+ ⇒ '(4 5 6 7 1 2 3)
+ (-rotate 16 '(1 2 3 4 5 6 7))
+ ⇒ '(6 7 1 2 3 4 5)
+
+ -- Function: -repeat (n x)
+ Return a list with X repeated N times. Return nil if N is less
+ than 1.
+
+ (-repeat 3 :a)
+ ⇒ '(:a :a :a)
+ (-repeat 1 :a)
+ ⇒ '(:a)
+ (-repeat 0 :a)
+ ⇒ nil
+
+ -- Function: -cons* (&rest args)
+ Make a new list from the elements of ARGS.
+
+ The last 2 members of ARGS are used as the final cons of the result
+ so if the final member of ARGS is not a list the result is a dotted
+ list.
+
+ (-cons* 1 2)
+ ⇒ '(1 . 2)
+ (-cons* 1 2 3)
+ ⇒ '(1 2 . 3)
+ (-cons* 1)
+ ⇒ 1
+
+ -- Function: -snoc (list elem &rest elements)
+ Append ELEM to the end of the list.
+
+ This is like ‘cons’, but operates on the end of list.
+
+ If ELEMENTS is non nil, append these to the list as well.
+
+ (-snoc '(1 2 3) 4)
+ ⇒ '(1 2 3 4)
+ (-snoc '(1 2 3) 4 5 6)
+ ⇒ '(1 2 3 4 5 6)
+ (-snoc '(1 2 3) '(4 5 6))
+ ⇒ '(1 2 3 (4 5 6))
+
+ -- Function: -interpose (sep list)
+ Return a new list of all elements in LIST separated by SEP.
+
+ (-interpose "-" '())
+ ⇒ '()
+ (-interpose "-" '("a"))
+ ⇒ '("a")
+ (-interpose "-" '("a" "b" "c"))
+ ⇒ '("a" "-" "b" "-" "c")
+
+ -- Function: -interleave (&rest lists)
+ Return a new list of the first item in each list, then the second
+ etc.
+
+ (-interleave '(1 2) '("a" "b"))
+ ⇒ '(1 "a" 2 "b")
+ (-interleave '(1 2) '("a" "b") '("A" "B"))
+ ⇒ '(1 "a" "A" 2 "b" "B")
+ (-interleave '(1 2 3) '("a" "b"))
+ ⇒ '(1 "a" 2 "b")
+
+ -- Function: -zip-with (fn list1 list2)
+ Zip the two lists LIST1 and LIST2 using a function FN. This
+ function is applied pairwise taking as first argument element of
+ LIST1 and as second argument element of LIST2 at corresponding
+ position.
+
+ The anaphoric form ‘--zip-with’ binds the elements from LIST1 as
+ symbol ‘it’, and the elements from LIST2 as symbol ‘other’.
+
+ (-zip-with '+ '(1 2 3) '(4 5 6))
+ ⇒ '(5 7 9)
+ (-zip-with 'cons '(1 2 3) '(4 5 6))
+ ⇒ '((1 . 4) (2 . 5) (3 . 6))
+ (--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde"))
+ ⇒ '("Batman and Robin" "Jekyll and Hyde")
+
+ -- Function: -zip (&rest lists)
+ Zip LISTS together. Group the head of each list, followed by the
+ second elements of each list, and so on. The lengths of the
+ returned groupings are equal to the length of the shortest input
+ list.
+
+ If two lists are provided as arguments, return the groupings as a
+ list of cons cells. Otherwise, return the groupings as a list of
+ lists.
+
+ Use ‘-zip-lists’ (*note -zip-lists::) if you need the return value
+ to always be a list of lists.
+
+ Alias: ‘-zip-pair’
+
+ See also: ‘-zip-lists’ (*note -zip-lists::)
+
+ (-zip '(1 2 3) '(4 5 6))
+ ⇒ '((1 . 4) (2 . 5) (3 . 6))
+ (-zip '(1 2 3) '(4 5 6 7))
+ ⇒ '((1 . 4) (2 . 5) (3 . 6))
+ (-zip '(1 2) '(3 4 5) '(6))
+ ⇒ '((1 3 6))
+
+ -- Function: -zip-lists (&rest lists)
+ Zip LISTS together. Group the head of each list, followed by the
+ second elements of each list, and so on. The lengths of the
+ returned groupings are equal to the length of the shortest input
+ list.
+
+ The return value is always list of lists, which is a difference
+ from ‘-zip-pair’ which returns a cons-cell in case two input lists
+ are provided.
+
+ See also: ‘-zip’ (*note -zip::)
+
+ (-zip-lists '(1 2 3) '(4 5 6))
+ ⇒ '((1 4) (2 5) (3 6))
+ (-zip-lists '(1 2 3) '(4 5 6 7))
+ ⇒ '((1 4) (2 5) (3 6))
+ (-zip-lists '(1 2) '(3 4 5) '(6))
+ ⇒ '((1 3 6))
+
+ -- Function: -zip-fill (fill-value &rest lists)
+ Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
+ lengths of the returned groupings are equal to the length of the
+ longest input list.
+
+ (-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9))
+ ⇒ '((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0))
+
+ -- Function: -unzip (lists)
+ Unzip LISTS.
+
+ This works just like ‘-zip’ (*note -zip::) but takes a list of
+ lists instead of a variable number of arguments, such that
+
+ (-unzip (-zip L1 L2 L3 ...))
+
+ is identity (given that the lists are the same length).
+
+ Note in particular that calling this on a list of two lists will
+ return a list of cons-cells such that the above identity works.
+
+ See also: ‘-zip’ (*note -zip::)
+
+ (-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g")))
+ ⇒ '((1 2 3) (a b c) ("e" "f" "g"))
+ (-unzip '((1 2) (3 4) (5 6) (7 8) (9 10)))
+ ⇒ '((1 3 5 7 9) (2 4 6 8 10))
+ (-unzip '((1 2) (3 4)))
+ ⇒ '((1 . 3) (2 . 4))
+
+ -- Function: -cycle (list)
+ Return an infinite 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 (-cycle '(1 2 3)) '(1 2))
+ ⇒ '((1 . 1) (2 . 2))
+
+ -- Function: -pad (fill-value &rest lists)
+ Appends FILL-VALUE to the end of each list in LISTS such that they
+ will all have the same length.
+
+ (-pad 0 '())
+ ⇒ '(nil)
+ (-pad 0 '(1))
+ ⇒ '((1))
+ (-pad 0 '(1 2 3) '(4 5))
+ ⇒ '((1 2 3) (4 5 0))
+
+ -- Function: -table (fn &rest lists)
+ Compute outer product of LISTS using function FN.
+
+ The function FN should have the same arity as the number of
+ supplied lists.
+
+ The outer product is computed by applying fn to all possible
+ combinations created by taking one element from each list in order.
+ The dimension of the result is (length lists).
+
+ See also: ‘-table-flat’ (*note -table-flat::)
+
+ (-table '* '(1 2 3) '(1 2 3))
+ ⇒ '((1 2 3) (2 4 6) (3 6 9))
+ (-table (lambda (a b) (-sum (-zip-with '* a b))) '((1 2) (3 4)) '((1 3) (2 4)))
+ ⇒ '((7 15) (10 22))
+ (apply '-table 'list (-repeat 3 '(1 2)))
+ ⇒ '((((1 1 1) (2 1 1)) ((1 2 1) (2 2 1))) (((1 1 2) (2 1 2)) ((1 2 2) (2 2 2))))
+
+ -- Function: -table-flat (fn &rest lists)
+ Compute flat outer product of LISTS using function FN.
+
+ The function FN should have the same arity as the number of
+ supplied lists.
+
+ The outer product is computed by applying fn to all possible
+ combinations created by taking one element from each list in order.
+ The results are flattened, ignoring the tensor structure of the
+ result. This is equivalent to calling:
+
+ (-flatten-n (1- (length lists)) (apply ’-table fn lists))
+
+ but the implementation here is much more efficient.
+
+ See also: ‘-flatten-n’ (*note -flatten-n::), ‘-table’ (*note
+ -table::)
+
+ (-table-flat 'list '(1 2 3) '(a b c))
+ ⇒ '((1 a) (2 a) (3 a) (1 b) (2 b) (3 b) (1 c) (2 c) (3 c))
+ (-table-flat '* '(1 2 3) '(1 2 3))
+ ⇒ '(1 2 3 2 4 6 3 6 9)
+ (apply '-table-flat 'list (-repeat 3 '(1 2)))
+ ⇒ '((1 1 1) (2 1 1) (1 2 1) (2 2 1) (1 1 2) (2 1 2) (1 2 2) (2 2 2))
+
+ -- Function: -first (pred list)
+ Return the first x in LIST where (PRED x) is non-nil, else nil.
+
+ To get the first item in the list no questions asked, use ‘car’.
+
+ Alias: ‘-find’
+
+ (-first 'even? '(1 2 3))
+ ⇒ 2
+ (-first 'even? '(1 3 5))
+ ⇒ nil
+ (-first 'null '(1 3 5))
+ ⇒ nil
+
+ -- Function: -some (pred list)
+ Return (PRED x) for the first LIST item where (PRED x) is non-nil,
+ else nil.
+
+ Alias: ‘-any’
+
+ (-some 'even? '(1 2 3))
+ ⇒ t
+ (-some 'null '(1 2 3))
+ ⇒ nil
+ (-some 'null '(1 2 nil))
+ ⇒ t
+
+ -- Function: -last (pred list)
+ Return the last x in LIST where (PRED x) is non-nil, else nil.
+
+ (-last 'even? '(1 2 3 4 5 6 3 3 3))
+ ⇒ 6
+ (-last 'even? '(1 3 7 5 9))
+ ⇒ nil
+ (--last (> (length it) 3) '("a" "looong" "word" "and" "short" "one"))
+ ⇒ "short"
+
+ -- Function: -first-item (list)
+ Return the first item of LIST, or nil on an empty list.
+
+ See also: ‘-second-item’ (*note -second-item::), ‘-last-item’
+ (*note -last-item::).
+
+ (fn LIST)
+
+ (-first-item '(1 2 3))
+ ⇒ 1
+ (-first-item nil)
+ ⇒ nil
+ (let ((list (list 1 2 3))) (setf (-first-item list) 5) list)
+ ⇒ '(5 2 3)
+
+ -- Function: -second-item (arg1)
+ Return the second item of LIST, or nil if LIST is too short.
+
+ See also: ‘-third-item’ (*note -third-item::).
+
+ (fn LIST)
+
+ (-second-item '(1 2 3))
+ ⇒ 2
+ (-second-item nil)
+ ⇒ nil
+
+ -- Function: -third-item (arg1)
+ Return the third item of LIST, or nil if LIST is too short.
+
+ See also: ‘-fourth-item’ (*note -fourth-item::).
+
+ (fn LIST)
+
+ (-third-item '(1 2 3))
+ ⇒ 3
+ (-third-item nil)
+ ⇒ nil
+
+ -- Function: -fourth-item (list)
+ Return the fourth item of LIST, or nil if LIST is too short.
+
+ See also: ‘-fifth-item’ (*note -fifth-item::).
+
+ (-fourth-item '(1 2 3 4))
+ ⇒ 4
+ (-fourth-item nil)
+ ⇒ nil
+
+ -- Function: -fifth-item (list)
+ Return the fifth item of LIST, or nil if LIST is too short.
+
+ See also: ‘-last-item’ (*note -last-item::).
+
+ (-fifth-item '(1 2 3 4 5))
+ ⇒ 5
+ (-fifth-item nil)
+ ⇒ nil
+
+ -- Function: -last-item (list)
+ Return the last item of LIST, or nil on an empty list.
+
+ (-last-item '(1 2 3))
+ ⇒ 3
+ (-last-item nil)
+ ⇒ nil
+ (let ((list (list 1 2 3))) (setf (-last-item list) 5) list)
+ ⇒ '(1 2 5)
+
+ -- Function: -butlast (list)
+ Return a list of all items in list except for the last.
+
+ (-butlast '(1 2 3))
+ ⇒ '(1 2)
+ (-butlast '(1 2))
+ ⇒ '(1)
+ (-butlast '(1))
+ ⇒ nil
+
+ -- Function: -sort (comparator list)
+ Sort LIST, stably, comparing elements using COMPARATOR. Return the
+ sorted list. LIST is NOT modified by side effects. COMPARATOR is
+ called with two elements of LIST, and should return non-nil if the
+ first element should sort before the second.
+
+ (-sort '< '(3 1 2))
+ ⇒ '(1 2 3)
+ (-sort '> '(3 1 2))
+ ⇒ '(3 2 1)
+ (--sort (< it other) '(3 1 2))
+ ⇒ '(1 2 3)
+
+ -- Function: -list (&rest args)
+ Return a list with ARGS.
+
+ If first item of ARGS is already a list, simply return ARGS. If
+ not, return a list with ARGS as elements.
+
+ (-list 1)
+ ⇒ '(1)
+ (-list 1 2 3)
+ ⇒ '(1 2 3)
+ (-list '(1 2 3))
+ ⇒ '(1 2 3)
+
+ -- Function: -fix (fn list)
+ Compute the (least) fixpoint of FN with initial input LIST.
+
+ FN is called at least once, results are compared with ‘equal’.
+
+ (-fix (lambda (l) (-non-nil (--mapcat (-split-at (/ (length it) 2) it) l))) '((1 2 3 4 5 6)))
+ ⇒ '((1) (2) (3) (4) (5) (6))
+ (let ((data '(("starwars" "scifi") ("jedi" "starwars" "warrior")))) (--fix (-uniq (--mapcat (cons it (cdr (assoc it data))) it)) '("jedi" "book")))
+ ⇒ '("jedi" "starwars" "warrior" "scifi" "book")
+
+\1f
+File: dash.info, Node: Tree operations, Next: Threading macros, Prev: Other list operations, Up: Functions
+
+2.11 Tree operations
+====================
+
+Functions pretending lists are trees.
+
+ -- Function: -tree-seq (branch children tree)
+ Return a sequence of the nodes in TREE, in depth-first search
+ order.
+
+ BRANCH is a predicate of one argument that returns non-nil if the
+ passed argument is a branch, that is, a node that can have
+ children.
+
+ CHILDREN is a function of one argument that returns the children of
+ the passed branch node.
+
+ Non-branch nodes are simply copied.
+
+ (-tree-seq 'listp 'identity '(1 (2 3) 4 (5 (6 7))))
+ ⇒ '((1 (2 3) 4 (5 (6 7))) 1 (2 3) 2 3 4 (5 (6 7)) 5 (6 7) 6 7)
+ (-tree-seq 'listp 'reverse '(1 (2 3) 4 (5 (6 7))))
+ ⇒ '((1 (2 3) 4 (5 (6 7))) (5 (6 7)) (6 7) 7 6 5 4 (2 3) 3 2 1)
+ (--tree-seq (vectorp it) (append it nil) [1 [2 3] 4 [5 [6 7]]])
+ ⇒ '([1 [2 3] 4 [5 [6 7]]] 1 [2 3] 2 3 4 [5 [6 7]] 5 [6 7] 6 7)
+
+ -- Function: -tree-map (fn tree)
+ Apply FN to each element of TREE while preserving the tree
+ structure.
+
+ (-tree-map '1+ '(1 (2 3) (4 (5 6) 7)))
+ ⇒ '(2 (3 4) (5 (6 7) 8))
+ (-tree-map '(lambda (x) (cons x (expt 2 x))) '(1 (2 3) 4))
+ ⇒ '((1 . 2) ((2 . 4) (3 . 8)) (4 . 16))
+ (--tree-map (length it) '("<body>" ("<p>" "text" "</p>") "</body>"))
+ ⇒ '(6 (3 4 4) 7)
+
+ -- Function: -tree-map-nodes (pred fun tree)
+ Call FUN on each node of TREE that satisfies PRED.
+
+ If PRED returns nil, continue descending down this node. If PRED
+ returns non-nil, apply FUN to this node and do not descend further.
+
+ (-tree-map-nodes 'vectorp (lambda (x) (-sum (append x nil))) '(1 [2 3] 4 (5 [6 7] 8)))
+ ⇒ '(1 5 4 (5 13 8))
+ (-tree-map-nodes 'keywordp (lambda (x) (symbol-name x)) '(1 :foo 4 ((5 6 :bar) :baz 8)))
+ ⇒ '(1 ":foo" 4 ((5 6 ":bar") ":baz" 8))
+ (--tree-map-nodes (eq (car-safe it) 'add-mode) (-concat it (list :mode 'emacs-lisp-mode)) '(with-mode emacs-lisp-mode (foo bar) (add-mode a b) (baz (add-mode c d))))
+ ⇒ '(with-mode emacs-lisp-mode (foo bar) (add-mode a b :mode emacs-lisp-mode) (baz (add-mode c d :mode emacs-lisp-mode)))
+
+ -- Function: -tree-reduce (fn tree)
+ Use FN to reduce elements of list TREE. If elements of TREE are
+ lists themselves, apply the reduction recursively.
+
+ FN is first applied to first element of the list and second
+ element, then on this result and third element from the list etc.
+
+ See ‘-reduce-r’ (*note -reduce-r::) for how exactly are lists of
+ zero or one element handled.
+
+ (-tree-reduce '+ '(1 (2 3) (4 5)))
+ ⇒ 15
+ (-tree-reduce 'concat '("strings" (" on" " various") ((" levels"))))
+ ⇒ "strings on various levels"
+ (--tree-reduce (cond ((stringp it) (concat it " " acc)) (t (let ((sn (symbol-name it))) (concat "<" sn ">" acc "</" sn ">")))) '(body (p "some words") (div "more" (b "bold") "words")))
+ ⇒ "<body><p>some words</p> <div>more <b>bold</b> words</div></body>"
+
+ -- Function: -tree-reduce-from (fn init-value tree)
+ Use FN to reduce elements of list TREE. If elements of TREE are
+ lists themselves, apply the reduction recursively.
+
+ FN is first applied to INIT-VALUE and first element of the list,
+ then on this result and second element from the list etc.
+
+ The initial value is ignored on cons pairs as they always contain
+ two elements.
+
+ (-tree-reduce-from '+ 1 '(1 (1 1) ((1))))
+ ⇒ 8
+ (--tree-reduce-from (-concat acc (list it)) nil '(1 (2 3 (4 5)) (6 7)))
+ ⇒ '((7 6) ((5 4) 3 2) 1)
+
+ -- Function: -tree-mapreduce (fn folder tree)
+ Apply FN to each element of TREE, and make a list of the results.
+ If elements of TREE are lists themselves, apply FN recursively to
+ elements of these nested lists.
+
+ Then reduce the resulting lists using FOLDER and initial value
+ INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::).
+
+ This is the same as calling ‘-tree-reduce’ (*note -tree-reduce::)
+ after ‘-tree-map’ (*note -tree-map::) but is twice as fast as it
+ only traverse the structure once.
+
+ (-tree-mapreduce 'list 'append '(1 (2 (3 4) (5 6)) (7 (8 9))))
+ ⇒ '(1 2 3 4 5 6 7 8 9)
+ (--tree-mapreduce 1 (+ it acc) '(1 (2 (4 9) (2 1)) (7 (4 3))))
+ ⇒ 9
+ (--tree-mapreduce 0 (max acc (1+ it)) '(1 (2 (4 9) (2 1)) (7 (4 3))))
+ ⇒ 3
+
+ -- Function: -tree-mapreduce-from (fn folder init-value tree)
+ Apply FN to each element of TREE, and make a list of the results.
+ If elements of TREE are lists themselves, apply FN recursively to
+ elements of these nested lists.
+
+ Then reduce the resulting lists using FOLDER and initial value
+ INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::).
+
+ This is the same as calling ‘-tree-reduce-from’ (*note
+ -tree-reduce-from::) after ‘-tree-map’ (*note -tree-map::) but is
+ twice as fast as it only traverse the structure once.
+
+ (-tree-mapreduce-from 'identity '* 1 '(1 (2 (3 4) (5 6)) (7 (8 9))))
+ ⇒ 362880
+ (--tree-mapreduce-from (+ it it) (cons it acc) nil '(1 (2 (4 9) (2 1)) (7 (4 3))))
+ ⇒ '(2 (4 (8 18) (4 2)) (14 (8 6)))
+ (concat "{" (--tree-mapreduce-from (cond ((-cons-pair? it) (concat (symbol-name (car it)) " -> " (symbol-name (cdr it)))) (t (concat (symbol-name it) " : {"))) (concat it (unless (or (equal acc "}") (equal (substring it (1- (length it))) "{")) ", ") acc) "}" '((elips-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam)))))
+ ⇒ "{elips-mode : {foo : {bar -> booze{, baz -> qux{, c-mode : {foo -> bla, bum -> bam}}"
+
+ -- Function: -clone (list)
+ Create a deep copy of LIST. The new list has the same elements and
+ structure but all cons are replaced with new ones. This is useful
+ when you need to clone a structure such as plist or alist.
+
+ (let* ((a '(1 2 3)) (b (-clone a))) (nreverse a) b)
+ ⇒ '(1 2 3)
+
+\1f
+File: dash.info, Node: Threading macros, Next: Binding, Prev: Tree operations, Up: Functions
+
+2.12 Threading macros
+=====================
+
+ -- Macro: -> (x &optional form &rest more)
+ Thread the expr through the forms. Insert X as the second item in
+ the first form, making a list of it if it is not a list already.
+ If there are more forms, insert the first form as the second item
+ in second form, etc.
+
+ (-> '(2 3 5))
+ ⇒ '(2 3 5)
+ (-> '(2 3 5) (append '(8 13)))
+ ⇒ '(2 3 5 8 13)
+ (-> '(2 3 5) (append '(8 13)) (-slice 1 -1))
+ ⇒ '(3 5 8)
+
+ -- Macro: ->> (x &optional form &rest more)
+ Thread the expr through the forms. Insert X as the last item in
+ the first form, making a list of it if it is not a list already.
+ If there are more forms, insert the first form as the last item in
+ second form, etc.
+
+ (->> '(1 2 3) (-map 'square))
+ ⇒ '(1 4 9)
+ (->> '(1 2 3) (-map 'square) (-remove 'even?))
+ ⇒ '(1 9)
+ (->> '(1 2 3) (-map 'square) (-reduce '+))
+ ⇒ 14
+
+ -- Macro: --> (x &rest forms)
+ Starting with the value of X, thread each expression through FORMS.
+
+ Insert X at the position signified by the symbol ‘it’ in the first
+ form. If there are more forms, insert the first form at the
+ position signified by ‘it’ in in second form, etc.
+
+ (--> "def" (concat "abc" it "ghi"))
+ ⇒ "abcdefghi"
+ (--> "def" (concat "abc" it "ghi") (upcase it))
+ ⇒ "ABCDEFGHI"
+ (--> "def" (concat "abc" it "ghi") upcase)
+ ⇒ "ABCDEFGHI"
+
+ -- Macro: -as-> (value variable &rest forms)
+ Starting with VALUE, thread VARIABLE through FORMS.
+
+ In the first form, bind VARIABLE to VALUE. In the second form,
+ bind VARIABLE to the result of the first form, and so forth.
+
+ (-as-> 3 my-var (1+ my-var) (list my-var) (mapcar (lambda (ele) (* 2 ele)) my-var))
+ ⇒ '(8)
+ (-as-> 3 my-var 1+)
+ ⇒ 4
+ (-as-> 3 my-var)
+ ⇒ 3
+
+ -- Macro: -some-> (x &optional form &rest more)
+ When expr is non-nil, thread it through the first form (via ‘->’
+ (*note ->::)), and when that result is non-nil, through the next
+ form, etc.
+
+ (-some-> '(2 3 5))
+ ⇒ '(2 3 5)
+ (-some-> 5 square)
+ ⇒ 25
+ (-some-> 5 even? square)
+ ⇒ nil
+
+ -- Macro: -some->> (x &optional form &rest more)
+ When expr is non-nil, thread it through the first form (via ‘->>’
+ (*note ->>::)), and when that result is non-nil, through the next
+ form, etc.
+
+ (-some->> '(1 2 3) (-map 'square))
+ ⇒ '(1 4 9)
+ (-some->> '(1 3 5) (-last 'even?) (+ 100))
+ ⇒ nil
+ (-some->> '(2 4 6) (-last 'even?) (+ 100))
+ ⇒ 106
+
+ -- Macro: -some--> (x &optional form &rest more)
+ When expr is non-nil, thread it through the first form (via ‘-->’
+ (*note -->::)), and when that result is non-nil, through the next
+ form, etc.
+
+ (-some--> "def" (concat "abc" it "ghi"))
+ ⇒ "abcdefghi"
+ (-some--> nil (concat "abc" it "ghi"))
+ ⇒ nil
+ (-some--> '(1 3 5) (-filter 'even? it) (append it it) (-map 'square it))
+ ⇒ nil
+
+\1f
+File: dash.info, Node: Binding, Next: Side-effects, Prev: Threading macros, Up: Functions
+
+2.13 Binding
+============
+
+Convenient versions of ‘let‘ and ‘let*‘ constructs combined with flow
+control.
+
+ -- Macro: -when-let (var-val &rest body)
+ If VAL evaluates to non-nil, bind it to VAR and execute body.
+
+ Note: binding is done according to ‘-let’ (*note -let::).
+
+ (fn (VAR VAL) &rest BODY)
+
+ (-when-let (match-index (string-match "d" "abcd")) (+ match-index 2))
+ ⇒ 5
+ (-when-let ((&plist :foo foo) (list :foo "foo")) foo)
+ ⇒ "foo"
+ (-when-let ((&plist :foo foo) (list :bar "bar")) foo)
+ ⇒ nil
+
+ -- Macro: -when-let* (vars-vals &rest body)
+ If all VALS evaluate to true, bind them to their corresponding VARS
+ and execute body. VARS-VALS should be a list of (VAR VAL) pairs.
+
+ Note: binding is done according to ‘-let*’ (*note -let*::). VALS
+ are evaluated sequentially, and evaluation stops after the first
+ nil VAL is encountered.
+
+ (-when-let* ((x 5) (y 3) (z (+ y 4))) (+ x y z))
+ ⇒ 15
+ (-when-let* ((x 5) (y nil) (z 7)) (+ x y z))
+ ⇒ nil
+
+ -- Macro: -if-let (var-val then &rest else)
+ If VAL evaluates to non-nil, bind it to VAR and do THEN, otherwise
+ do ELSE.
+
+ Note: binding is done according to ‘-let’ (*note -let::).
+
+ (fn (VAR VAL) THEN &rest ELSE)
+
+ (-if-let (match-index (string-match "d" "abc")) (+ match-index 3) 7)
+ ⇒ 7
+ (--if-let (even? 4) it nil)
+ ⇒ t
+
+ -- Macro: -if-let* (vars-vals then &rest else)
+ If all VALS evaluate to true, bind them to their corresponding VARS
+ and do THEN, otherwise do ELSE. VARS-VALS should be a list of (VAR
+ VAL) pairs.
+
+ Note: binding is done according to ‘-let*’ (*note -let*::). VALS
+ are evaluated sequentially, and evaluation stops after the first
+ nil VAL is encountered.
+
+ (-if-let* ((x 5) (y 3) (z 7)) (+ x y z) "foo")
+ ⇒ 15
+ (-if-let* ((x 5) (y nil) (z 7)) (+ x y z) "foo")
+ ⇒ "foo"
+ (-if-let* (((_ _ x) '(nil nil 7))) x)
+ ⇒ 7
+
+ -- Macro: -let (varlist &rest body)
+ Bind variables according to VARLIST then eval BODY.
+
+ VARLIST is a list of lists of the form (PATTERN SOURCE). Each
+ PATTERN is matched against the SOURCE "structurally". SOURCE is
+ only evaluated once for each PATTERN. Each PATTERN is matched
+ recursively, and can therefore contain sub-patterns which are
+ matched against corresponding sub-expressions of SOURCE.
+
+ All the SOURCEs are evalled before any symbols are bound (i.e. "in
+ parallel").
+
+ If VARLIST only contains one (PATTERN SOURCE) element, you can
+ optionally specify it using a vector and discarding the outer-most
+ parens. Thus
+
+ (-let ((PATTERN SOURCE)) ..)
+
+ becomes
+
+ (-let [PATTERN SOURCE] ..).
+
+ ‘-let’ (*note -let::) uses a convention of not binding places
+ (symbols) starting with _ whenever it’s possible. You can use this
+ to skip over entries you don’t care about. However, this is not
+ *always* possible (as a result of implementation) and these symbols
+ might get bound to undefined values.
+
+ Following is the overview of supported patterns. Remember that
+ patterns can be matched recursively, so every a, b, aK in the
+ following can be a matching construct and not necessarily a
+ symbol/variable.
+
+ Symbol:
+
+ a - bind the SOURCE to A. This is just like regular ‘let’.
+
+ Conses and lists:
+
+ (a) - bind ‘car’ of cons/list to A
+
+ (a . b) - bind car of cons to A and ‘cdr’ to B
+
+ (a b) - bind car of list to A and ‘cadr’ to B
+
+ (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3
+ ...
+
+ (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to
+ REST.
+
+ Vectors:
+
+ [a] - bind 0th element of a non-list sequence to A (works with
+ vectors, strings, bit arrays...)
+
+ [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st
+ to A1, 2nd to A2, ... If the PATTERN is shorter than SOURCE, the
+ values at places not in PATTERN are ignored. If the PATTERN is
+ longer than SOURCE, an ‘error’ is thrown.
+
+ [a1 a2 a3 ... &rest rest] - as above, but bind the rest of the
+ sequence to REST. This is conceptually the same as improper list
+ matching (a1 a2 ... aN . rest)
+
+ Key/value stores:
+
+ (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE plist to aK. If the value is not found, aK is nil. Uses
+ ‘plist-get’ to fetch values.
+
+ (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE alist to aK. If the value is not found, aK is nil. Uses
+ ‘assoc’ to fetch values.
+
+ (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE hash table to aK. If the value is not found, aK is nil.
+ Uses ‘gethash’ to fetch values.
+
+ Further, special keyword &keys supports "inline" matching of
+ plist-like key-value pairs, similarly to &keys keyword of
+ ‘cl-defun’.
+
+ (a1 a2 ... aN &keys key1 b1 ... keyN bK)
+
+ This binds N values from the list to a1 ... aN, then interprets
+ the cdr as a plist (see key/value matching above).
+
+ A shorthand notation for kv-destructuring exists which allows the
+ patterns be optionally left out and derived from the key name in
+ the following fashion:
+
+ - a key :foo is converted into ‘foo’ pattern, - a key ’bar is
+ converted into ‘bar’ pattern, - a key "baz" is converted into ‘baz’
+ pattern.
+
+ That is, the entire value under the key is bound to the derived
+ variable without any further destructuring.
+
+ This is possible only when the form following the key is not a
+ valid pattern (i.e. not a symbol, a cons cell or a vector).
+ Otherwise the matching proceeds as usual and in case of an invalid
+ spec fails with an error.
+
+ Thus the patterns are normalized as follows:
+
+ ;; derive all the missing patterns (&plist :foo ’bar "baz") =>
+ (&plist :foo foo ’bar bar "baz" baz)
+
+ ;; we can specify some but not others (&plist :foo ’bar
+ explicit-bar) => (&plist :foo foo ’bar explicit-bar)
+
+ ;; nothing happens, we store :foo in x (&plist :foo x) => (&plist
+ :foo x)
+
+ ;; nothing happens, we match recursively (&plist :foo (a b c)) =>
+ (&plist :foo (a b c))
+
+ You can name the source using the syntax SYMBOL &as PATTERN. This
+ syntax works with lists (proper or improper), vectors and all types
+ of maps.
+
+ (list &as a b c) (list 1 2 3)
+
+ binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
+
+ Similarly:
+
+ (bounds &as beg . end) (cons 1 2)
+
+ binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
+
+ (items &as first . rest) (list 1 2 3)
+
+ binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
+
+ [vect &as _ b c] [1 2 3]
+
+ binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as
+ usual).
+
+ (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
+
+ binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and
+ &hash.
+
+ This is especially useful when we want to capture the result of a
+ computation and destructure at the same time. Consider the form
+ (function-returning-complex-structure) returning a list of two
+ vectors with two items each. We want to capture this entire result
+ and pass it to another computation, but at the same time we want to
+ get the second item from each vector. We can achieve it with
+ pattern
+
+ (result &as [_ a] [_ b]) (function-returning-complex-structure)
+
+ Note: Clojure programmers may know this feature as the ":as
+ binding". The difference is that we put the &as at the front
+ because we need to support improper list binding.
+
+ (-let (([a (b c) d] [1 (2 3) 4])) (list a b c d))
+ ⇒ '(1 2 3 4)
+ (-let [(a b c . d) (list 1 2 3 4 5 6)] (list a b c d))
+ ⇒ '(1 2 3 (4 5 6))
+ (-let [(&plist :foo foo :bar bar) (list :baz 3 :foo 1 :qux 4 :bar 2)] (list foo bar))
+ ⇒ '(1 2)
+
+ -- Macro: -let* (varlist &rest body)
+ Bind variables according to VARLIST then eval BODY.
+
+ VARLIST is a list of lists of the form (PATTERN SOURCE). Each
+ PATTERN is matched against the SOURCE structurally. SOURCE is only
+ evaluated once for each PATTERN.
+
+ Each SOURCE can refer to the symbols already bound by this VARLIST.
+ This is useful if you want to destructure SOURCE recursively but
+ also want to name the intermediate structures.
+
+ See ‘-let’ (*note -let::) for the list of all possible patterns.
+
+ (-let* (((a . b) (cons 1 2)) ((c . d) (cons 3 4))) (list a b c d))
+ ⇒ '(1 2 3 4)
+ (-let* (((a . b) (cons 1 (cons 2 3))) ((c . d) b)) (list a b c d))
+ ⇒ '(1 (2 . 3) 2 3)
+ (-let* (((&alist "foo" foo "bar" bar) (list (cons "foo" 1) (cons "bar" (list 'a 'b 'c)))) ((a b c) bar)) (list foo a b c bar))
+ ⇒ '(1 a b c (a b c))
+
+ -- Macro: -lambda (match-form &rest body)
+ Return a lambda which destructures its input as MATCH-FORM and
+ executes BODY.
+
+ Note that you have to enclose the MATCH-FORM in a pair of parens,
+ such that:
+
+ (-lambda (x) body) (-lambda (x y ...) body)
+
+ has the usual semantics of ‘lambda’. Furthermore, these get
+ translated into normal lambda, so there is no performance penalty.
+
+ See ‘-let’ (*note -let::) for the description of destructuring
+ mechanism.
+
+ (-map (-lambda ((x y)) (+ x y)) '((1 2) (3 4) (5 6)))
+ ⇒ '(3 7 11)
+ (-map (-lambda ([x y]) (+ x y)) '([1 2] [3 4] [5 6]))
+ ⇒ '(3 7 11)
+ (funcall (-lambda ((_ . a) (_ . b)) (-concat a b)) '(1 2 3) '(4 5 6))
+ ⇒ '(2 3 5 6)
+
+ -- Macro: -setq (&rest forms)
+ Bind each MATCH-FORM to the value of its VAL.
+
+ MATCH-FORM destructuring is done according to the rules of ‘-let’
+ (*note -let::).
+
+ This macro allows you to bind multiple variables by destructuring
+ the value, so for example:
+
+ (-setq (a b) x (&plist :c c) plist)
+
+ expands roughly speaking to the following code
+
+ (setq a (car x) b (cadr x) c (plist-get plist :c))
+
+ Care is taken to only evaluate each VAL once so that in case of
+ multiple assignments it does not cause unexpected side effects.
+
+ (fn [MATCH-FORM VAL]...)
+
+ (progn (-setq a 1) a)
+ ⇒ 1
+ (progn (-setq (a b) (list 1 2)) (list a b))
+ ⇒ '(1 2)
+ (progn (-setq (&plist :c c) (list :c "c")) c)
+ ⇒ "c"
+
+\1f
+File: dash.info, Node: Side-effects, Next: Destructive operations, Prev: Binding, Up: Functions
+
+2.14 Side-effects
+=================
+
+Functions iterating over lists for side-effect only.
+
+ -- Function: -each (list fn)
+ Call FN with every item in LIST. Return nil, used for side-effects
+ only.
+
+ (let (s) (-each '(1 2 3) (lambda (item) (setq s (cons item s)))))
+ ⇒ nil
+ (let (s) (-each '(1 2 3) (lambda (item) (setq s (cons item s)))) s)
+ ⇒ '(3 2 1)
+ (let (s) (--each '(1 2 3) (setq s (cons it s))) s)
+ ⇒ '(3 2 1)
+
+ -- Function: -each-while (list pred fn)
+ Call FN with every item in LIST while (PRED item) is non-nil.
+ Return nil, used for side-effects only.
+
+ (let (s) (-each-while '(2 4 5 6) 'even? (lambda (item) (push item s))) s)
+ ⇒ '(4 2)
+ (let (s) (--each-while '(1 2 3 4) (< it 3) (push it s)) s)
+ ⇒ '(2 1)
+ (let ((s 0)) (--each-while '(1 3 4 5) (odd? it) (setq s (+ s it))) s)
+ ⇒ 4
+
+ -- Function: -each-indexed (list fn)
+ Call (FN index item) for each item in LIST.
+
+ In the anaphoric form ‘--each-indexed’, the index is exposed as
+ symbol ‘it-index’.
+
+ See also: ‘-map-indexed’ (*note -map-indexed::).
+
+ (let (s) (-each-indexed '(a b c) (lambda (index item) (setq s (cons (list item index) s)))) s)
+ ⇒ '((c 2) (b 1) (a 0))
+ (let (s) (--each-indexed '(a b c) (setq s (cons (list it it-index) s))) s)
+ ⇒ '((c 2) (b 1) (a 0))
+
+ -- Function: -each-r (list fn)
+ Call FN with every item in LIST in reversed order. Return nil,
+ used for side-effects only.
+
+ (let (s) (-each-r '(1 2 3) (lambda (item) (setq s (cons item s)))))
+ ⇒ nil
+ (let (s) (-each-r '(1 2 3) (lambda (item) (setq s (cons item s)))) s)
+ ⇒ '(1 2 3)
+ (let (s) (--each-r '(1 2 3) (setq s (cons it s))) s)
+ ⇒ '(1 2 3)
+
+ -- Function: -each-r-while (list pred fn)
+ Call FN with every item in reversed LIST while (PRED item) is
+ non-nil. Return nil, used for side-effects only.
+
+ (let (s) (-each-r-while '(2 4 5 6) 'even? (lambda (item) (!cons item s))) s)
+ ⇒ '(6)
+ (let (s) (--each-r-while '(1 2 3 4) (>= it 3) (!cons it s)) s)
+ ⇒ '(3 4)
+
+ -- Function: -dotimes (num fn)
+ Repeatedly calls FN (presumably for side-effects) passing in
+ integers from 0 through NUM-1.
+
+ (let (s) (-dotimes 3 (lambda (n) (!cons n s))) s)
+ ⇒ '(2 1 0)
+ (let (s) (--dotimes 5 (!cons it s)) s)
+ ⇒ '(4 3 2 1 0)
+
+ -- Macro: -doto (eval-initial-value &rest forms)
+ Eval a form, then insert that form as the 2nd argument to other
+ forms. The EVAL-INITIAL-VALUE form is evaluated once. Its result
+ is passed to FORMS, which are then evaluated sequentially. Returns
+ the target form.
+
+ (-doto '(1 2 3) (!cdr) (!cdr))
+ ⇒ '(3)
+ (-doto '(1 . 2) (setcar 3) (setcdr 4))
+ ⇒ '(3 . 4)
+
+ -- Macro: --doto (eval-initial-value &rest forms)
+ Anaphoric form of ‘-doto’ (*note -doto::). Note: ‘it’ is not
+ required in each form.
+
+ (gethash "key" (--doto (make-hash-table :test 'equal) (puthash "key" "value" it)))
+ ⇒ "value"
+
+\1f
+File: dash.info, Node: Destructive operations, Next: Function combinators, Prev: Side-effects, Up: Functions
+
+2.15 Destructive operations
+===========================
+
+ -- Macro: !cons (car cdr)
+ Destructive: Set CDR to the cons of CAR and CDR.
+
+ (let (l) (!cons 5 l) l)
+ ⇒ '(5)
+ (let ((l '(3))) (!cons 5 l) l)
+ ⇒ '(5 3)
+
+ -- Macro: !cdr (list)
+ Destructive: Set LIST to the cdr of LIST.
+
+ (let ((l '(3))) (!cdr l) l)
+ ⇒ '()
+ (let ((l '(3 5))) (!cdr l) l)
+ ⇒ '(5)
+
+\1f
+File: dash.info, Node: Function combinators, Prev: Destructive operations, Up: Functions
+
+2.16 Function combinators
+=========================
+
+These combinators require Emacs 24 for its lexical scope. So they are
+offered in a separate package: ‘dash-functional‘.
+
+ -- Function: -partial (fn &rest args)
+ Take a function FN and fewer than the normal arguments to FN, and
+ return a fn that takes a variable number of additional ARGS. When
+ called, the returned function calls FN with ARGS first and then
+ additional args.
+
+ (funcall (-partial '- 5) 3)
+ ⇒ 2
+ (funcall (-partial '+ 5 2) 3)
+ ⇒ 10
+
+ -- Function: -rpartial (fn &rest args)
+ Takes a function FN and fewer than the normal arguments to FN, and
+ returns a fn that takes a variable number of additional ARGS. When
+ called, the returned function calls FN with the additional args
+ first and then ARGS.
+
+ (funcall (-rpartial '- 5) 8)
+ ⇒ 3
+ (funcall (-rpartial '- 5 2) 10)
+ ⇒ 3
+
+ -- Function: -juxt (&rest fns)
+ Takes a list of functions and returns a fn that is the
+ juxtaposition of those fns. The returned fn takes a variable
+ number of args, and returns a list containing the result of
+ applying each fn to the args (left-to-right).
+
+ (funcall (-juxt '+ '-) 3 5)
+ ⇒ '(8 -2)
+ (-map (-juxt 'identity 'square) '(1 2 3))
+ ⇒ '((1 1) (2 4) (3 9))
+
+ -- Function: -compose (&rest fns)
+ Takes a list of functions and returns a fn that is the composition
+ of those fns. The returned fn takes a variable number of
+ arguments, and returns the result of applying each fn to the result
+ of applying the previous fn to the arguments (right-to-left).
+
+ (funcall (-compose 'square '+) 2 3)
+ ⇒ (square (+ 2 3))
+ (funcall (-compose 'identity 'square) 3)
+ ⇒ (square 3)
+ (funcall (-compose 'square 'identity) 3)
+ ⇒ (square 3)
+
+ -- Function: -applify (fn)
+ Changes an n-arity function FN to a 1-arity function that expects a
+ list with n items as arguments
+
+ (-map (-applify '+) '((1 1 1) (1 2 3) (5 5 5)))
+ ⇒ '(3 6 15)
+ (-map (-applify (lambda (a b c) `(,a (,b (,c))))) '((1 1 1) (1 2 3) (5 5 5)))
+ ⇒ '((1 (1 (1))) (1 (2 (3))) (5 (5 (5))))
+ (funcall (-applify '<) '(3 6))
+ ⇒ t
+
+ -- Function: -on (operator transformer)
+ Return a function of two arguments that first applies TRANSFORMER
+ to each of them and then applies OPERATOR on the results (in the
+ same order).
+
+ In types: (b -> b -> c) -> (a -> b) -> a -> a -> c
+
+ (-sort (-on '< 'length) '((1 2 3) (1) (1 2)))
+ ⇒ '((1) (1 2) (1 2 3))
+ (-min-by (-on '> 'length) '((1 2 3) (4) (1 2)))
+ ⇒ '(4)
+ (-min-by (-on 'string-lessp 'number-to-string) '(2 100 22))
+ ⇒ 22
+
+ -- Function: -flip (func)
+ Swap the order of arguments for binary function FUNC.
+
+ In types: (a -> b -> c) -> b -> a -> c
+
+ (funcall (-flip '<) 2 1)
+ ⇒ t
+ (funcall (-flip '-) 3 8)
+ ⇒ 5
+ (-sort (-flip '<) '(4 3 6 1))
+ ⇒ '(6 4 3 1)
+
+ -- Function: -const (c)
+ Return a function that returns C ignoring any additional arguments.
+
+ In types: a -> b -> a
+
+ (funcall (-const 2) 1 3 "foo")
+ ⇒ 2
+ (-map (-const 1) '("a" "b" "c" "d"))
+ ⇒ '(1 1 1 1)
+ (-sum (-map (-const 1) '("a" "b" "c" "d")))
+ ⇒ 4
+
+ -- Macro: -cut (&rest params)
+ Take n-ary function and n arguments and specialize some of them.
+ Arguments denoted by <> will be left unspecialized.
+
+ See SRFI-26 for detailed description.
+
+ (funcall (-cut list 1 <> 3 <> 5) 2 4)
+ ⇒ '(1 2 3 4 5)
+ (-map (-cut funcall <> 5) '(1+ 1- (lambda (x) (/ 1.0 x))))
+ ⇒ '(6 4 0.2)
+ (-map (-cut <> 1 2 3) (list 'list 'vector 'string))
+ ⇒ '((1 2 3) [1 2 3] "\ 1\ 2\ 3")
+
+ -- Function: -not (pred)
+ Take a unary predicate PRED and return a unary predicate that
+ returns t if PRED returns nil and nil if PRED returns non-nil.
+
+ (funcall (-not 'even?) 5)
+ ⇒ t
+ (-filter (-not (-partial '< 4)) '(1 2 3 4 5 6 7 8))
+ ⇒ '(1 2 3 4)
+
+ -- Function: -orfn (&rest preds)
+ Take list of unary predicates PREDS and return a unary predicate
+ with argument x that returns non-nil if at least one of the PREDS
+ returns non-nil on x.
+
+ In types: [a -> Bool] -> a -> Bool
+
+ (-filter (-orfn 'even? (-partial (-flip '<) 5)) '(1 2 3 4 5 6 7 8 9 10))
+ ⇒ '(1 2 3 4 6 8 10)
+ (funcall (-orfn 'stringp 'even?) "foo")
+ ⇒ t
+
+ -- Function: -andfn (&rest preds)
+ Take list of unary predicates PREDS and return a unary predicate
+ with argument x that returns non-nil if all of the PREDS returns
+ non-nil on x.
+
+ In types: [a -> Bool] -> a -> Bool
+
+ (funcall (-andfn (-cut < <> 10) 'even?) 6)
+ ⇒ t
+ (funcall (-andfn (-cut < <> 10) 'even?) 12)
+ ⇒ nil
+ (-filter (-andfn (-not 'even?) (-cut >= 5 <>)) '(1 2 3 4 5 6 7 8 9 10))
+ ⇒ '(1 3 5)
+
+ -- Function: -iteratefn (fn n)
+ Return a function FN composed N times with itself.
+
+ FN is a unary function. If you need to use a function of higher
+ arity, use ‘-applify’ (*note -applify::) first to turn it into a
+ unary function.
+
+ With n = 0, this acts as identity function.
+
+ In types: (a -> a) -> Int -> a -> a.
+
+ This function satisfies the following law:
+
+ (funcall (-iteratefn fn n) init) = (-last-item (-iterate fn init
+ (1+ n))).
+
+ (funcall (-iteratefn (lambda (x) (* x x)) 3) 2)
+ ⇒ 256
+ (funcall (-iteratefn '1+ 3) 1)
+ ⇒ 4
+ (funcall (-iteratefn 'cdr 3) '(1 2 3 4 5))
+ ⇒ '(4 5)
+
+ -- Function: -fixfn (fn &optional equal-test halt-test)
+ Return a function that computes the (least) fixpoint of FN.
+
+ FN must be a unary function. The returned lambda takes a single
+ argument, X, the initial value for the fixpoint iteration. The
+ iteration halts when either of the following conditions is
+ satisfied:
+
+ 1. Iteration converges to the fixpoint, with equality being tested
+ using EQUAL-TEST. If EQUAL-TEST is not specified, ‘equal’ is used.
+ For functions over the floating point numbers, it may be necessary
+ to provide an appropriate approximate comparison test.
+
+ 2. HALT-TEST returns a non-nil value. HALT-TEST defaults to a
+ simple counter that returns t after ‘-fixfn-max-iterations’, to
+ guard against infinite iteration. Otherwise, HALT-TEST must be a
+ function that accepts a single argument, the current value of X,
+ and returns non-nil as long as iteration should continue. In this
+ way, a more sophisticated convergence test may be supplied by the
+ caller.
+
+ The return value of the lambda is either the fixpoint or, if
+ iteration halted before converging, a cons with car ‘halted’ and
+ cdr the final output from HALT-TEST.
+
+ In types: (a -> a) -> a -> a.
+
+ (funcall (-fixfn 'cos 'approx-equal) 0.7)
+ ⇒ 0.7390851332151607
+ (funcall (-fixfn (lambda (x) (expt (+ x 10) 0.25))) 2.0)
+ ⇒ 1.8555845286409378
+ (funcall (-fixfn 'sin 'approx-equal) 0.1)
+ ⇒ '(halted . t)
+
+ -- Function: -prodfn (&rest fns)
+ Take a list of n functions and return a function that takes a list
+ of length n, applying i-th function to i-th element of the input
+ list. Returns a list of length n.
+
+ In types (for n=2): ((a -> b), (c -> d)) -> (a, c) -> (b, d)
+
+ This function satisfies the following laws:
+
+ (-compose (-prodfn f g ...) (-prodfn f’ g’ ...)) = (-prodfn
+ (-compose f f’) (-compose g g’) ...) (-prodfn f g ...) = (-juxt
+ (-compose f (-partial ’nth 0)) (-compose g (-partial ’nth 1)) ...)
+ (-compose (-prodfn f g ...) (-juxt f’ g’ ...)) = (-juxt (-compose
+ f f’) (-compose g g’) ...) (-compose (-partial ’nth n) (-prod f1
+ f2 ...)) = (-compose fn (-partial ’nth n))
+
+ (funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3))
+ ⇒ '(2 1 "3")
+ (-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8)))
+ ⇒ '((2 1) (4 3) (6 5) (8 7))
+ (apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15")))
+ ⇒ 18
+
+\1f
+File: dash.info, Node: Development, Next: Index, Prev: Functions, Up: Top
+
+3 Development
+*************
+
+The dash repository is hosted on GitHub:
+<https://github.com/magnars/dash.el>
+
+* Menu:
+
+* Contribute:: How to contribute
+* Changes:: List of significant changes by version
+* Contributors:: List of contributors
+
+\1f
+File: dash.info, Node: Contribute, Next: Changes, Up: Development
+
+3.1 Contribute
+==============
+
+Yes, please do. Pure functions in the list manipulation realm only,
+please. There’s a suite of tests in dev/examples.el, so remember to add
+tests for your function, or it might get broken later.
+
+ Run the tests with ‘./run-tests.sh’. Create the docs with
+‘./create-docs.sh’. I highly recommend that you install these as a
+pre-commit hook, so that the tests are always running and the docs are
+always in sync:
+
+cp pre-commit.sh .git/hooks/pre-commit
+
+ Oh, and don’t edit ‘README.md’ directly, it is auto-generated.
+Change ‘readme-template.md’ or ‘examples-to-docs.el’ instead. The same
+goes for the info manual.
+
+\1f
+File: dash.info, Node: Changes, Next: Contributors, Prev: Contribute, Up: Development
+
+3.2 Changes
+===========
+
+Changes in 2.10:
+
+ • Add ‘-let’ destructuring to ‘-if-let’ and ‘-when-let’ (Fredrik
+ Bergroth)
+
+Changes in 2.9:
+
+ • Add ‘-let’, ‘-let*’ and ‘-lambda’ with destructuring
+ • Add ‘-tree-seq’ and ‘-tree-map-nodes’
+ • Add ‘-non-nil’
+ • Add ‘-fix’
+ • Add ‘-fixfn’ (dash-functional 1.2)
+ • Add ‘-copy’ (Wilfred Hughes)
+
+Changes in 2.8:
+
+ • Add ‘-butlast’
+
+Changes in 2.7:
+
+ • ‘-zip’ now supports more than two lists (Steve Lamb)
+ • Add ‘-cycle’, ‘-pad’, ‘-annotate’, ‘-zip-fill’ (Steve Lamb)
+ • Add ‘-table’, ‘-table-flat’ (finite cartesian product)
+ • Add ‘-flatten-n’
+ • ‘-slice’ now supports "step" argument
+ • Add functional combinators ‘-iteratefn’, ‘-prodfn’
+ • Add ‘-replace’, ‘-splice’, ‘-splice-list’ which generalize
+ ‘-replace-at’ and ‘-insert-at’
+ • Add ‘-compose’, ‘-iteratefn’ and ‘-prodfn’ (dash-functional 1.1)
+
+Changes in 2.6:
+
+ • Add ‘-is-prefix-p’, ‘-is-suffix-p’, ‘-is-infix-p’ (Matus Goljer)
+ • Add ‘-iterate’, ‘-unfold’ (Matus Goljer)
+ • Add ‘-split-on’, ‘-split-when’ (Matus Goljer)
+ • Add ‘-find-last-index’ (Matus Goljer)
+ • Add ‘-list’ (Johan Andersson)
+
+Changes in 2.5:
+
+ • Add ‘-same-items?’ (Johan Andersson)
+ • A few bugfixes
+
+Changes in 2.4:
+
+ • Add ‘-snoc’ (Matus Goljer)
+ • Add ‘-replace-at’, ‘-update-at’, ‘-remove-at’, and
+ ‘-remove-at-indices’ (Matus Goljer)
+
+Changes in 2.3:
+
+ • Add tree operations (Matus Goljer)
+ • Make font-lock optional
+
+Changes in 2.2:
+
+ • Add ‘-compose’ (Christina Whyte)
+
+Changes in 2.1:
+
+ • Add indexing operations (Matus Goljer)
+
+Changes in 2.0:
+
+ • Split out ‘dash-functional.el’ (Matus Goljer)
+ • Add ‘-andfn’, ‘-orfn’, ‘-not’, ‘-cut’, ‘-const’, ‘-flip’ and ‘-on’.
+ (Matus Goljer)
+ • Fix ‘-min’, ‘-max’, ‘-min-by’ and ‘-max-by’ (Matus Goljer)
+
+Changes in 1.8:
+
+ • Add ‘-first-item’ and ‘-last-item’ (Wilfred Hughes)
+
+Changes in 1.7:
+
+ • Add ‘-rotate’ (Matus Goljer)
+
+Changes in 1.6:
+
+ • Add ‘-min’, ‘-max’, ‘-min-by’ and ‘-max-by’ (Johan Andersson)
+
+Changes in 1.5:
+
+ • Add ‘-sum’ and ‘-product’ (Johan Andersson)
+
+Changes in 1.4:
+
+ • Add ‘-sort’
+ • Add ‘-reduce-r’ (Matus Goljer)
+ • Add ‘-reduce-r-from’ (Matus Goljer)
+
+Changes in 1.3:
+
+ • Add ‘-partition-in-steps’
+ • Add ‘-partition-all-in-steps’
+
+Changes in 1.2:
+
+ • Add ‘-last’ (Matus Goljer)
+ • Add ‘-insert-at’ (Emanuel Evans)
+ • Add ‘-when-let’ and ‘-if-let’ (Emanuel Evans)
+ • Add ‘-when-let*’ and ‘-if-let*’ (Emanuel Evans)
+ • Some bugfixes
+
+\1f
+File: dash.info, Node: Contributors, Prev: Changes, Up: Development
+
+3.3 Contributors
+================
+
+ • Matus Goljer (https://github.com/Fuco1) contributed lots of
+ features and functions.
+ • Takafumi Arakaki (https://github.com/tkf) contributed ‘-group-by’.
+ • tali713 (https://github.com/tali713) is the author of ‘-applify’.
+ • VÃctor M. Valenzuela (https://github.com/vemv) contributed
+ ‘-repeat’.
+ • Nic Ferrier (https://github.com/nicferrier) contributed ‘-cons*’.
+ • Wilfred Hughes (https://github.com/Wilfred) contributed ‘-slice’,
+ ‘-first-item’ and ‘-last-item’.
+ • Emanuel Evans (https://github.com/shosti) contributed ‘-if-let’,
+ ‘-when-let’ and ‘-insert-at’.
+ • Johan Andersson (https://github.com/rejeep) contributed ‘-sum’,
+ ‘-product’ and ‘-same-items?’
+ • Christina Whyte (https://github.com/kurisuwhyte) contributed
+ ‘-compose’
+ • Steve Lamb (https://github.com/steventlamb) contributed ‘-cycle’,
+ ‘-pad’, ‘-annotate’, ‘-zip-fill’ and an n-ary version of ‘-zip’.
+ • Fredrik Bergroth (https://github.com/fbergroth) made the ‘-if-let’
+ family use ‘-let’ destructuring and improved script for generating
+ documentation.
+ • Mark Oteiza (https://github.com/holomorph) contributed the script
+ to create an info manual.
+ • Vasilij Schneidermann (https://github.com/wasamasa) contributed
+ ‘-some’.
+ • William West (https://github.com/occidens) made ‘-fixfn’ more
+ robust at handling floats.
+
+ Thanks!
+
+\1f
+File: dash.info, Node: Index, Prev: Development, Up: Top
+
+Index
+*****
+
+\0\b[index\0\b]
+* Menu:
+
+* !cdr: Destructive operations.
+ (line 14)
+* !cons: Destructive operations.
+ (line 6)
+* -->: Threading macros. (line 32)
+* --doto: Side-effects. (line 83)
+* ->: Threading macros. (line 6)
+* ->>: Threading macros. (line 19)
+* -all?: Predicates. (line 18)
+* -andfn: Function combinators.
+ (line 138)
+* -annotate: Maps. (line 79)
+* -any?: Predicates. (line 6)
+* -applify: Function combinators.
+ (line 55)
+* -as->: Threading macros. (line 46)
+* -butlast: Other list operations.
+ (line 340)
+* -clone: Tree operations. (line 122)
+* -common-prefix: Reductions. (line 223)
+* -common-suffix: Reductions. (line 233)
+* -compose: Function combinators.
+ (line 42)
+* -concat: List to list. (line 22)
+* -cons*: Other list operations.
+ (line 30)
+* -const: Function combinators.
+ (line 92)
+* -contains?: Predicates. (line 57)
+* -copy: Maps. (line 134)
+* -count: Reductions. (line 151)
+* -cut: Function combinators.
+ (line 104)
+* -cycle: Other list operations.
+ (line 168)
+* -difference: Set operations. (line 20)
+* -distinct: Set operations. (line 62)
+* -dotimes: Side-effects. (line 63)
+* -doto: Side-effects. (line 72)
+* -drop: Sublist selection. (line 128)
+* -drop-last: Sublist selection. (line 142)
+* -drop-while: Sublist selection. (line 171)
+* -each: Side-effects. (line 8)
+* -each-indexed: Side-effects. (line 30)
+* -each-r: Side-effects. (line 43)
+* -each-r-while: Side-effects. (line 54)
+* -each-while: Side-effects. (line 19)
+* -elem-index: Indexing. (line 9)
+* -elem-indices: Indexing. (line 21)
+* -fifth-item: Other list operations.
+ (line 320)
+* -filter: Sublist selection. (line 8)
+* -find-index: Indexing. (line 32)
+* -find-indices: Indexing. (line 60)
+* -find-last-index: Indexing. (line 46)
+* -first: Other list operations.
+ (line 234)
+* -first-item: Other list operations.
+ (line 271)
+* -fix: Other list operations.
+ (line 376)
+* -fixfn: Function combinators.
+ (line 175)
+* -flatten: List to list. (line 33)
+* -flatten-n: List to list. (line 55)
+* -flip: Function combinators.
+ (line 80)
+* -fourth-item: Other list operations.
+ (line 310)
+* -grade-down: Indexing. (line 81)
+* -grade-up: Indexing. (line 71)
+* -group-by: Partitioning. (line 187)
+* -if-let: Binding. (line 36)
+* -if-let*: Binding. (line 49)
+* -inits: Reductions. (line 203)
+* -insert-at: List to list. (line 109)
+* -interleave: Other list operations.
+ (line 68)
+* -interpose: Other list operations.
+ (line 58)
+* -intersection: Set operations. (line 32)
+* -is-infix?: Predicates. (line 110)
+* -is-prefix?: Predicates. (line 86)
+* -is-suffix?: Predicates. (line 98)
+* -iterate: Unfolding. (line 9)
+* -iteratefn: Function combinators.
+ (line 152)
+* -juxt: Function combinators.
+ (line 31)
+* -keep: List to list. (line 8)
+* -lambda: Binding. (line 252)
+* -last: Other list operations.
+ (line 261)
+* -last-item: Other list operations.
+ (line 330)
+* -let: Binding. (line 65)
+* -let*: Binding. (line 232)
+* -list: Other list operations.
+ (line 363)
+* -map: Maps. (line 10)
+* -map-first: Maps. (line 37)
+* -map-indexed: Maps. (line 65)
+* -map-last: Maps. (line 51)
+* -map-when: Maps. (line 21)
+* -mapcat: Maps. (line 123)
+* -max: Reductions. (line 267)
+* -max-by: Reductions. (line 277)
+* -min: Reductions. (line 243)
+* -min-by: Reductions. (line 253)
+* -non-nil: Sublist selection. (line 79)
+* -none?: Predicates. (line 30)
+* -not: Function combinators.
+ (line 117)
+* -on: Function combinators.
+ (line 66)
+* -only-some?: Predicates. (line 42)
+* -orfn: Function combinators.
+ (line 126)
+* -pad: Other list operations.
+ (line 179)
+* -partial: Function combinators.
+ (line 9)
+* -partition: Partitioning. (line 74)
+* -partition-after-item: Partitioning. (line 177)
+* -partition-after-pred: Partitioning. (line 145)
+* -partition-all: Partitioning. (line 86)
+* -partition-all-in-steps: Partitioning. (line 109)
+* -partition-before-item: Partitioning. (line 167)
+* -partition-before-pred: Partitioning. (line 156)
+* -partition-by: Partitioning. (line 121)
+* -partition-by-header: Partitioning. (line 132)
+* -partition-in-steps: Partitioning. (line 97)
+* -permutations: Set operations. (line 52)
+* -powerset: Set operations. (line 44)
+* -prodfn: Function combinators.
+ (line 209)
+* -product: Reductions. (line 181)
+* -reduce: Reductions. (line 46)
+* -reduce-from: Reductions. (line 8)
+* -reduce-r: Reductions. (line 65)
+* -reduce-r-from: Reductions. (line 27)
+* -reductions: Reductions. (line 119)
+* -reductions-from: Reductions. (line 87)
+* -reductions-r: Reductions. (line 135)
+* -reductions-r-from: Reductions. (line 103)
+* -remove: Sublist selection. (line 23)
+* -remove-at: List to list. (line 145)
+* -remove-at-indices: List to list. (line 158)
+* -remove-first: Sublist selection. (line 37)
+* -remove-item: Sublist selection. (line 67)
+* -remove-last: Sublist selection. (line 52)
+* -repeat: Other list operations.
+ (line 19)
+* -replace: List to list. (line 67)
+* -replace-at: List to list. (line 120)
+* -replace-first: List to list. (line 81)
+* -replace-last: List to list. (line 95)
+* -rotate: Other list operations.
+ (line 8)
+* -rpartial: Function combinators.
+ (line 20)
+* -running-product: Reductions. (line 191)
+* -running-sum: Reductions. (line 169)
+* -same-items?: Predicates. (line 72)
+* -second-item: Other list operations.
+ (line 286)
+* -select-by-indices: Sublist selection. (line 185)
+* -select-column: Sublist selection. (line 215)
+* -select-columns: Sublist selection. (line 196)
+* -separate: Partitioning. (line 63)
+* -setq: Binding. (line 274)
+* -slice: Sublist selection. (line 85)
+* -snoc: Other list operations.
+ (line 44)
+* -some: Other list operations.
+ (line 248)
+* -some-->: Threading macros. (line 83)
+* -some->: Threading macros. (line 59)
+* -some->>: Threading macros. (line 71)
+* -sort: Other list operations.
+ (line 350)
+* -splice: Maps. (line 90)
+* -splice-list: Maps. (line 110)
+* -split-at: Partitioning. (line 8)
+* -split-on: Partitioning. (line 28)
+* -split-when: Partitioning. (line 46)
+* -split-with: Partitioning. (line 17)
+* -sum: Reductions. (line 159)
+* -table: Other list operations.
+ (line 190)
+* -table-flat: Other list operations.
+ (line 209)
+* -tails: Reductions. (line 213)
+* -take: Sublist selection. (line 101)
+* -take-last: Sublist selection. (line 114)
+* -take-while: Sublist selection. (line 156)
+* -third-item: Other list operations.
+ (line 298)
+* -tree-map: Tree operations. (line 28)
+* -tree-map-nodes: Tree operations. (line 39)
+* -tree-mapreduce: Tree operations. (line 84)
+* -tree-mapreduce-from: Tree operations. (line 103)
+* -tree-reduce: Tree operations. (line 52)
+* -tree-reduce-from: Tree operations. (line 69)
+* -tree-seq: Tree operations. (line 8)
+* -unfold: Unfolding. (line 25)
+* -union: Set operations. (line 8)
+* -unzip: Other list operations.
+ (line 146)
+* -update-at: List to list. (line 132)
+* -when-let: Binding. (line 9)
+* -when-let*: Binding. (line 23)
+* -zip: Other list operations.
+ (line 95)
+* -zip-fill: Other list operations.
+ (line 138)
+* -zip-lists: Other list operations.
+ (line 119)
+* -zip-with: Other list operations.
+ (line 79)
+
+
+\1f
+Tag Table:
+Node: Top\7f947
+Node: Installation\7f2424
+Node: Using in a package\7f2991
+Node: Fontification of special variables\7f3352
+Node: Functions\7f4056
+Node: Maps\7f5267
+Ref: -map\7f5562
+Ref: -map-when\7f5903
+Ref: -map-first\7f6481
+Ref: -map-last\7f6959
+Ref: -map-indexed\7f7432
+Ref: -annotate\7f7912
+Ref: -splice\7f8402
+Ref: -splice-list\7f9183
+Ref: -mapcat\7f9645
+Ref: -copy\7f10021
+Node: Sublist selection\7f10225
+Ref: -filter\7f10418
+Ref: -remove\7f10870
+Ref: -remove-first\7f11276
+Ref: -remove-last\7f11803
+Ref: -remove-item\7f12324
+Ref: -non-nil\7f12719
+Ref: -slice\7f12878
+Ref: -take\7f13410
+Ref: -take-last\7f13819
+Ref: -drop\7f14252
+Ref: -drop-last\7f14682
+Ref: -take-while\7f15110
+Ref: -drop-while\7f15636
+Ref: -select-by-indices\7f16160
+Ref: -select-columns\7f16674
+Ref: -select-column\7f17380
+Node: List to list\7f17844
+Ref: -keep\7f18036
+Ref: -concat\7f18539
+Ref: -flatten\7f18836
+Ref: -flatten-n\7f19595
+Ref: -replace\7f19982
+Ref: -replace-first\7f20445
+Ref: -replace-last\7f20942
+Ref: -insert-at\7f21432
+Ref: -replace-at\7f21759
+Ref: -update-at\7f22149
+Ref: -remove-at\7f22640
+Ref: -remove-at-indices\7f23128
+Node: Reductions\7f23710
+Ref: -reduce-from\7f23879
+Ref: -reduce-r-from\7f24645
+Ref: -reduce\7f25412
+Ref: -reduce-r\7f26141
+Ref: -reductions-from\7f27012
+Ref: -reductions-r-from\7f27727
+Ref: -reductions\7f28452
+Ref: -reductions-r\7f29077
+Ref: -count\7f29712
+Ref: -sum\7f29936
+Ref: -running-sum\7f30125
+Ref: -product\7f30418
+Ref: -running-product\7f30627
+Ref: -inits\7f30940
+Ref: -tails\7f31188
+Ref: -common-prefix\7f31435
+Ref: -common-suffix\7f31732
+Ref: -min\7f32029
+Ref: -min-by\7f32255
+Ref: -max\7f32778
+Ref: -max-by\7f33003
+Node: Unfolding\7f33531
+Ref: -iterate\7f33770
+Ref: -unfold\7f34215
+Node: Predicates\7f35023
+Ref: -any?\7f35147
+Ref: -all?\7f35467
+Ref: -none?\7f35797
+Ref: -only-some?\7f36099
+Ref: -contains?\7f36584
+Ref: -same-items?\7f36973
+Ref: -is-prefix?\7f37358
+Ref: -is-suffix?\7f37681
+Ref: -is-infix?\7f38004
+Node: Partitioning\7f38358
+Ref: -split-at\7f38546
+Ref: -split-with\7f38831
+Ref: -split-on\7f39234
+Ref: -split-when\7f39910
+Ref: -separate\7f40550
+Ref: -partition\7f40992
+Ref: -partition-all\7f41444
+Ref: -partition-in-steps\7f41872
+Ref: -partition-all-in-steps\7f42369
+Ref: -partition-by\7f42854
+Ref: -partition-by-header\7f43236
+Ref: -partition-after-pred\7f43840
+Ref: -partition-before-pred\7f44184
+Ref: -partition-before-item\7f44535
+Ref: -partition-after-item\7f44846
+Ref: -group-by\7f45152
+Node: Indexing\7f45589
+Ref: -elem-index\7f45791
+Ref: -elem-indices\7f46186
+Ref: -find-index\7f46569
+Ref: -find-last-index\7f47058
+Ref: -find-indices\7f47562
+Ref: -grade-up\7f47970
+Ref: -grade-down\7f48373
+Node: Set operations\7f48783
+Ref: -union\7f48966
+Ref: -difference\7f49408
+Ref: -intersection\7f49825
+Ref: -powerset\7f50262
+Ref: -permutations\7f50475
+Ref: -distinct\7f50775
+Node: Other list operations\7f51153
+Ref: -rotate\7f51378
+Ref: -repeat\7f51748
+Ref: -cons*\7f52011
+Ref: -snoc\7f52398
+Ref: -interpose\7f52811
+Ref: -interleave\7f53109
+Ref: -zip-with\7f53478
+Ref: -zip\7f54195
+Ref: -zip-lists\7f55027
+Ref: -zip-fill\7f55728
+Ref: -unzip\7f56051
+Ref: -cycle\7f56796
+Ref: -pad\7f57198
+Ref: -table\7f57521
+Ref: -table-flat\7f58310
+Ref: -first\7f59318
+Ref: -some\7f59690
+Ref: -last\7f59999
+Ref: -first-item\7f60333
+Ref: -second-item\7f60749
+Ref: -third-item\7f61029
+Ref: -fourth-item\7f61307
+Ref: -fifth-item\7f61573
+Ref: -last-item\7f61835
+Ref: -butlast\7f62127
+Ref: -sort\7f62374
+Ref: -list\7f62863
+Ref: -fix\7f63194
+Node: Tree operations\7f63734
+Ref: -tree-seq\7f63930
+Ref: -tree-map\7f64788
+Ref: -tree-map-nodes\7f65231
+Ref: -tree-reduce\7f66081
+Ref: -tree-reduce-from\7f66963
+Ref: -tree-mapreduce\7f67564
+Ref: -tree-mapreduce-from\7f68424
+Ref: -clone\7f69710
+Node: Threading macros\7f70038
+Ref: ->\7f70183
+Ref: ->>\7f70674
+Ref: -->\7f71179
+Ref: -as->\7f71735
+Ref: -some->\7f72190
+Ref: -some->>\7f72564
+Ref: -some-->\7f73000
+Node: Binding\7f73471
+Ref: -when-let\7f73683
+Ref: -when-let*\7f74168
+Ref: -if-let\7f74691
+Ref: -if-let*\7f75086
+Ref: -let\7f75703
+Ref: -let*\7f81793
+Ref: -lambda\7f82733
+Ref: -setq\7f83530
+Node: Side-effects\7f84346
+Ref: -each\7f84540
+Ref: -each-while\7f84947
+Ref: -each-indexed\7f85405
+Ref: -each-r\7f85923
+Ref: -each-r-while\7f86356
+Ref: -dotimes\7f86731
+Ref: -doto\7f87034
+Ref: --doto\7f87462
+Node: Destructive operations\7f87737
+Ref: !cons\7f87910
+Ref: !cdr\7f88116
+Node: Function combinators\7f88311
+Ref: -partial\7f88585
+Ref: -rpartial\7f88979
+Ref: -juxt\7f89382
+Ref: -compose\7f89814
+Ref: -applify\7f90367
+Ref: -on\7f90798
+Ref: -flip\7f91324
+Ref: -const\7f91636
+Ref: -cut\7f91975
+Ref: -not\7f92461
+Ref: -orfn\7f92771
+Ref: -andfn\7f93205
+Ref: -iteratefn\7f93700
+Ref: -fixfn\7f94403
+Ref: -prodfn\7f95966
+Node: Development\7f97034
+Node: Contribute\7f97383
+Node: Changes\7f98131
+Node: Contributors\7f101129
+Node: Index\7f102748
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
--- /dev/null
+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.
+\1f
+File: dir, Node: Top This is the top of the INFO tree
+
+ This (the Directory node) gives a menu of major topics.
+ Typing "q" exits, "H" lists all Info commands, "d" returns here,
+ "h" gives a primer for first-timers,
+ "mEmacs<Return>" visits the Emacs manual, etc.
+
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+
+* Menu:
+
+Emacs
+* Dash: (dash.info). A modern list library for GNU Emacs