emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/dash ba6b4a6115 4/8: Merge branch 'blc/stefan'


From: ELPA Syncer
Subject: [elpa] externals/dash ba6b4a6115 4/8: Merge branch 'blc/stefan'
Date: Sat, 4 Mar 2023 17:57:35 -0500 (EST)

branch: externals/dash
commit ba6b4a6115701251dc627a6c19cbb5a272c0a413
Merge: 3df46d7d9f 2acdae698e
Author: Basil L. Contovounesios <contovob@tcd.ie>
Commit: Basil L. Contovounesios <contovob@tcd.ie>

    Merge branch 'blc/stefan'
---
 NEWS.md            |  11 +-
 README.md          | 217 +++++++++++++++++---------
 dash.el            | 290 +++++++++++++++++++++++------------
 dash.texi          | 271 +++++++++++++++++++++++----------
 dev/examples.el    | 439 ++++++++++++++++++++++++++++++++++++++++++++++-------
 readme-template.md |  13 --
 6 files changed, 922 insertions(+), 319 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index ab08c1ee76..5ac57ea155 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,6 +8,13 @@ See the end of the file for license conditions.
 
 ### From 2.19.1 to 2.20.0
 
+#### Deprecations
+
+- Calling `-zip` with two arguments now emits a warning.  This
+  long-discouraged calling convention remains supported, but the
+  caller is now referred to the equivalent `-zip-pair` instead (Stefan
+  Monnier, #400).
+
 #### Fixes
 
 - Fixed a regression from `2.18` in `-take` that caused it to
@@ -132,8 +139,8 @@ 
https://github.com/magnars/dash.el/wiki/Obsoletion-of-dash-functional.el
 - Sped up `-uniq` by using hash-tables when possible (@cireu, #305).
 - Fixed `-inits` to be non-destructive (@SwiftLawnGnome, #313).
 - Fixed indent rules for `-some->` and family (@wbolster, #321).
-- Added `-zip-lists` which always returns a list of proper lists, even for two
-  input lists (see issue #135).
+- Added `-zip-lists` which always returns a list of proper lists, even
+  for two input lists, in contrast to `-zip` (see issue #135).
 
 ### From 2.15 to 2.16
 
diff --git a/README.md b/README.md
index b9712bf118..e4ccf91d0e 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,6 @@ See the end of the file for license conditions.
 ## Contents
 
 * [Change log](#change-log)
-  * [Upcoming breaking change!](#upcoming-breaking-change)
 * [Installation](#installation)
 * [Functions](#functions)
 * [Contribute](#contribute)
@@ -25,18 +24,6 @@ See the end of the file for license conditions.
 
 See the [`NEWS.md`](NEWS.md) file.
 
-### Upcoming breaking change!
-
-- For backward compatibility reasons, `-zip` when called with two
-  lists returns a list of cons cells, rather than a list of proper
-  lists.  This is a clunky API, and may be changed in a future release
-  to always return a list of proper lists, as `-zip-lists` currently
-  does.
-
-  **N.B.:** Do not rely on the current behavior of `-zip` for two
-  lists.  Instead, use `-zip-pair` for a list of cons cells, and
-  `-zip-lists` for a list of proper lists.
-
 ## Installation
 
 Dash is available on [GNU ELPA](https://elpa.gnu.org/), [GNU-devel
@@ -287,9 +274,12 @@ Other list functions not fit to be classified elsewhere.
 * [`-interleave`](#-interleave-rest-lists) `(&rest lists)`
 * [`-iota`](#-iota-count-optional-start-step) `(count &optional start step)`
 * [`-zip-with`](#-zip-with-fn-list1-list2) `(fn list1 list2)`
-* [`-zip`](#-zip-rest-lists) `(&rest lists)`
+* [`-zip-pair`](#-zip-pair-list1-list2) `(list1 list2)`
 * [`-zip-lists`](#-zip-lists-rest-lists) `(&rest lists)`
+* [`-zip-lists-fill`](#-zip-lists-fill-fill-value-rest-lists) `(fill-value 
&rest lists)`
+* [`-zip`](#-zip-rest-lists) `(&rest lists)`
 * [`-zip-fill`](#-zip-fill-fill-value-rest-lists) `(fill-value &rest lists)`
+* [`-unzip-lists`](#-unzip-lists-lists) `(lists)`
 * [`-unzip`](#-unzip-lists) `(lists)`
 * [`-pad`](#-pad-fill-value-rest-lists) `(fill-value &rest lists)`
 * [`-table`](#-table-fn-rest-lists) `(fn &rest lists)`
@@ -927,28 +917,38 @@ See also: [`-map-when`](#-map-when-pred-rep-list)
 
 #### -remove-at `(n list)`
 
-Return a list with element at `n`th position in `list` removed.
+Return `list` with its element at index `n` removed.
+That is, remove any element selected as (nth `n` `list`) from `list`
+and return the result.
 
-See also: [`-remove-at-indices`](#-remove-at-indices-indices-list), 
[`-remove`](#-remove-pred-list)
+This is a non-destructive operation: parts of `list` (but not
+necessarily all of it) are copied as needed to avoid
+destructively modifying it.
+
+See also: [`-remove-at-indices`](#-remove-at-indices-indices-list), 
[`-remove`](#-remove-pred-list).
 
 ```el
-(-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")
+(-remove-at 0 '(a b c)) ;; => (b c)
+(-remove-at 1 '(a b c)) ;; => (a c)
+(-remove-at 2 '(a b c)) ;; => (a b)
 ```
 
 #### -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`.
+Return `list` with its elements at `indices` removed.
+That is, for each index `i` in `indices`, remove any element selected
+as (nth `i` `list`) from `list`.
+
+This is a non-destructive operation: parts of `list` (but not
+necessarily all of it) are copied as needed to avoid
+destructively modifying it.
 
-See also: [`-remove-at`](#-remove-at-n-list), [`-remove`](#-remove-pred-list)
+See also: [`-remove-at`](#-remove-at-n-list), [`-remove`](#-remove-pred-list).
 
 ```el
-(-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")
+(-remove-at-indices '(0) '(a b c d e)) ;; => (b c d e)
+(-remove-at-indices '(1 3) '(a b c d e)) ;; => (a c e)
+(-remove-at-indices '(4 0 2) '(a b c d e)) ;; => (b d)
 ```
 
 ## Reductions
@@ -1326,7 +1326,7 @@ from the beginning.
 ```el
 (-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))
+(-zip-lists (-cycle '(3)) '(1 2)) ;; => ((3 1) (3 2))
 ```
 
 ## Predicates
@@ -1982,53 +1982,52 @@ the `apl` language.
 
 #### -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.
+Zip `list1` and `list2` into a new list using the function `fn`.
+That is, apply `fn` pairwise taking as first argument the next
+element of `list1` and as second argument the next element of `list2`
+at the corresponding position.  The result is as long as the
+shorter list.
+
+This function's anaphoric counterpart is `--zip-with`.
 
-The anaphoric form `--zip-with` binds the elements from `list1` as symbol `it`,
-and the elements from `list2` as symbol `other`.
+For other zips, see also [`-zip-lists`](#-zip-lists-rest-lists) and 
[`-zip-fill`](#-zip-fill-fill-value-rest-lists).
 
 ```el
-(-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")
+(-zip-with #'+ '(1 2 3 4) '(5 6 7)) ;; => (6 8 10)
+(-zip-with #'cons '(1 2 3) '(4 5 6 7)) ;; => ((1 . 4) (2 . 5) (3 . 6))
+(--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde)) ;; => 
("Batman & Robin" "Jekyll & Hyde")
 ```
 
-#### -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.
+#### -zip-pair `(list1 list2)`
 
-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.
+Zip `list1` and `list2` together.
 
-Use [`-zip-lists`](#-zip-lists-rest-lists) if you need the return value to 
always be a list
-of lists.
+Make a pair with the head of each list, followed by a pair with
+the second element of each list, and so on.  The number of pairs
+returned is equal to the length of the shorter input list.
 
-Alias: `-zip-pair`
-
-See also: [`-zip-lists`](#-zip-lists-rest-lists)
+See also: [`-zip-lists`](#-zip-lists-rest-lists).
 
 ```el
-(-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))
+(-zip-pair '(1 2 3 4) '(5 6 7)) ;; => ((1 . 5) (2 . 6) (3 . 7))
+(-zip-pair '(1 2 3) '(4 5 6)) ;; => ((1 . 4) (2 . 5) (3 . 6))
+(-zip-pair '(1 2) '(3)) ;; => ((1 . 3))
 ```
 
 #### -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.
+Zip `lists` together.
+
+Group the head of each list, followed by the second element of
+each list, and so on.  The number of returned groupings is equal
+to the length of the shortest input list, and the length of each
+grouping is equal to the number of input `lists`.
 
-The return value is always list of lists, which is a difference
-from `-zip-pair` which returns a cons-cell in case two input
-lists are provided.
+The return value is always a list of proper lists, in contrast to
+[`-zip`](#-zip-rest-lists) which returns a list of dotted pairs when only two 
input
+`lists` are provided.
 
-See also: [`-zip`](#-zip-rest-lists)
+See also: [`-zip-pair`](#-zip-pair-list1-list2).
 
 ```el
 (-zip-lists '(1 2 3) '(4 5 6)) ;; => ((1 4) (2 5) (3 6))
@@ -2036,36 +2035,106 @@ See also: [`-zip`](#-zip-rest-lists)
 (-zip-lists '(1 2) '(3 4 5) '(6)) ;; => ((1 3 6))
 ```
 
+#### -zip-lists-fill `(fill-value &rest lists)`
+
+Zip `lists` together, padding shorter lists with `fill-value`.
+This is like [`-zip-lists`](#-zip-lists-rest-lists) (which see), except it 
retains all
+elements at positions beyond the end of the shortest list.  The
+number of returned groupings is equal to the length of the
+longest input list, and the length of each grouping is equal to
+the number of input `lists`.
+
+```el
+(-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) ;; => ((1 3 6) (2 4 0) (0 5 0))
+(-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) ;; => ((1 3 5) (2 4 6))
+(-zip-lists-fill 0 '(1 2 3) nil) ;; => ((1 0) (2 0) (3 0))
+```
+
+#### -zip `(&rest lists)`
+
+Zip `lists` together.
+
+Group the head of each list, followed by the second element of
+each list, and so on.  The number of returned groupings is equal
+to the length of the shortest input list, and the number of items
+in each grouping is equal to the number of input `lists`.
+
+If only two `lists` are provided as arguments, return the groupings
+as a list of dotted pairs.  Otherwise, return the groupings as a
+list of proper lists.
+
+Since the return value changes form depending on the number of
+arguments, it is generally recommended to use 
[`-zip-lists`](#-zip-lists-rest-lists)
+instead, or [`-zip-pair`](#-zip-pair-list1-list2) if a list of dotted pairs is 
desired.
+
+See also: [`-unzip`](#-unzip-lists).
+
+```el
+(-zip '(1 2 3 4) '(5 6 7) '(8 9)) ;; => ((1 5 8) (2 6 9))
+(-zip '(1 2 3) '(4 5 6) '(7 8 9)) ;; => ((1 4 7) (2 5 8) (3 6 9))
+(-zip '(1 2 3)) ;; => ((1) (2) (3))
+```
+
 #### -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 `lists` together, padding shorter lists with `fill-value`.
+This is like [`-zip`](#-zip-rest-lists) (which see), except it retains all 
elements
+at positions beyond the end of the shortest list.  The number of
+returned groupings is equal to the length of the longest input
+list, and the length of each grouping is equal to the number of
+input `lists`.
+
+Since the return value changes form depending on the number of
+arguments, it is generally recommended to use 
[`-zip-lists-fill`](#-zip-lists-fill-fill-value-rest-lists)
+instead, unless a list of dotted pairs is explicitly desired.
+
+```el
+(-zip-fill 0 '(1 2 3) '(4 5)) ;; => ((1 . 4) (2 . 5) (3 . 0))
+(-zip-fill 0 () '(1 2 3)) ;; => ((0 . 1) (0 . 2) (0 . 3))
+(-zip-fill 0 '(1 2) '(3 4) '(5 6)) ;; => ((1 3 5) (2 4 6))
+```
+
+#### -unzip-lists `(lists)`
+
+Unzip `lists`.
+
+This works just like [`-zip-lists`](#-zip-lists-rest-lists) (which see), but 
takes a list
+of lists instead of a variable number of arguments, such that
+
+    (-unzip-lists (-zip-lists `args`...))
+
+is identity (given that the lists comprising `args` are of the same
+length).
 
 ```el
-(-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) ;; => ((1 . 6) (2 . 7) (3 . 8) (4 . 9) 
(5 . 0))
+(-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) ;; => ((1 2) (3 4) (5 6))
+(-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) ;; => ((1 4 6 8) (2 5 7 9))
+(-unzip-lists '((1 2 3) (4 5 6))) ;; => ((1 4) (2 5) (3 6))
 ```
 
 #### -unzip `(lists)`
 
 Unzip `lists`.
 
-This works just like [`-zip`](#-zip-rest-lists) but takes a list of lists 
instead of
-a variable number of arguments, such that
+This works just like [`-zip`](#-zip-rest-lists) (which see), but takes a list 
of
+lists instead of a variable number of arguments, such that
 
     (-unzip (-zip `l1` `l2` `l3` ...))
 
-is identity (given that the lists are the same length).
+is identity (given that the lists are of the same length, and
+that [`-zip`](#-zip-rest-lists) is not called with two arguments, because of 
the
+caveat described in its docstring).
 
-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.
+Note in particular that calling [`-unzip`](#-unzip-lists) on a list of two 
lists
+will return a list of dotted pairs.
 
-See also: [`-zip`](#-zip-rest-lists)
+Since the return value changes form depending on the number of
+`lists`, it is generally recommended to use 
[`-unzip-lists`](#-unzip-lists-lists) instead.
 
 ```el
-(-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))
+(-unzip (-zip '(1 2) '(3 4) '(5 6))) ;; => ((1 . 2) (3 . 4) (5 . 6))
+(-unzip '((1 2 3) (4 5 6))) ;; => ((1 . 4) (2 . 5) (3 . 6))
+(-unzip '((1 2 3) (4 5) (6 7) (8 9))) ;; => ((1 4 6 8) (2 5 7 9))
 ```
 
 #### -pad `(fill-value &rest lists)`
@@ -3204,9 +3273,9 @@ This function satisfies the following laws:
     = (-compose fn (-partial #'nth n))
 
 ```el
-(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
+(funcall (-prodfn #'1+ #'1- #'number-to-string) '(1 2 3)) ;; => (2 1 "3")
+(-map (-prodfn #'1- #'1+) '((1 2) (3 4) (5 6))) ;; => ((0 3) (2 5) (4 7))
+(apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) ;; => 6
 ```
 
 ## Contribute
diff --git a/dash.el b/dash.el
index 6efdc24ea4..ef4f9d3263 100644
--- a/dash.el
+++ b/dash.el
@@ -1,6 +1,6 @@
 ;;; dash.el --- A modern list library for Emacs  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
 
 ;; Author: Magnar Sveen <magnars@gmail.com>
 ;; Version: 2.19.1
@@ -536,7 +536,8 @@ This function's anaphoric counterpart is `--remove-first'.
 See also `-map-first', `-remove-item', and `-remove-last'."
   (--remove-first (funcall pred it) list))
 
-(defalias '-reject-first '-remove-first)
+;; TODO: #'-quoting the macro upsets Emacs 24.
+(defalias '-reject-first #'-remove-first)
 (defalias '--reject-first '--remove-first)
 
 (defmacro --remove-last (form list)
@@ -706,7 +707,7 @@ See also: `-map-last'"
 (defmacro --mapcat (form list)
   "Anaphoric form of `-mapcat'."
   (declare (debug (form form)))
-  `(apply 'append (--map ,form ,list)))
+  `(apply #'append (--map ,form ,list)))
 
 (defun -mapcat (fn list)
   "Return the concatenation of the result of mapping FN over LIST.
@@ -772,7 +773,7 @@ is just used as the tail of the new list.
 
 \(fn &rest SEQUENCES)")
 
-(defalias '-copy 'copy-sequence
+(defalias '-copy #'copy-sequence
   "Create a shallow copy of LIST.
 
 \(fn LIST)")
@@ -1298,28 +1299,41 @@ See also: `-map-when'"
   `(-update-at ,n (lambda (it) (ignore it) ,form) ,list))
 
 (defun -remove-at (n list)
-  "Return a list with element at Nth position in LIST removed.
+  "Return LIST with its element at index N removed.
+That is, remove any element selected as (nth N LIST) from LIST
+and return the result.
 
-See also: `-remove-at-indices', `-remove'"
+This is a non-destructive operation: parts of LIST (but not
+necessarily all of it) are copied as needed to avoid
+destructively modifying it.
+
+See also: `-remove-at-indices', `-remove'."
   (declare (pure t) (side-effect-free t))
-  (-remove-at-indices (list n) list))
+  (if (zerop n)
+      (cdr list)
+    (--remove-first (= it-index 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.
+  "Return LIST with its elements at INDICES removed.
+That is, for each index I in INDICES, remove any element selected
+as (nth I LIST) from LIST.
+
+This is a non-destructive operation: parts of LIST (but not
+necessarily all of it) are copied as needed to avoid
+destructively modifying it.
 
-See also: `-remove-at', `-remove'"
+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))))
+  (setq indices (--drop-while (< it 0) (-sort #'< indices)))
+  (let ((i (pop indices)) res)
+    (--each-while list i
+      (pop list)
+      (if (/= it-index i)
+          (push it res)
+        (while (and indices (= (car indices) i))
+          (pop indices))
+        (setq i (pop indices))))
+    (nconc (nreverse res) list)))
 
 (defmacro --split-with (pred list)
   "Anaphoric form of `-split-with'."
@@ -1603,104 +1617,193 @@ elements of LIST.  Keys are compared by `equal'."
       (nreverse result))))
 
 (defmacro --zip-with (form list1 list2)
-  "Anaphoric form of `-zip-with'.
+  "Zip LIST1 and LIST2 into a new list according to FORM.
+That is, evaluate FORM for each item pair from the two lists, and
+return the list of results.  The result is as long as the shorter
+list.
 
-Each element in turn of LIST1 is bound to `it', and of LIST2 to
-`other', before evaluating FORM."
+Each element of LIST1 and each element of LIST2 in turn are bound
+pairwise to `it' and `other', respectively, and their index
+within the list to `it-index', before evaluating FORM.
+
+This is the anaphoric counterpart to `-zip-with'."
   (declare (debug (form form form)))
   (let ((r (make-symbol "result"))
-        (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)))
+    `(let ((,l2 ,list2) ,r)
+       (--each-while ,list1 ,l2
+         (let ((other (pop ,l2)))
+           (ignore other)
+           (push ,form ,r)))
        (nreverse ,r))))
 
 (defun -zip-with (fn list1 list2)
-  "Zip 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.
+  "Zip LIST1 and LIST2 into a new list using the function FN.
+That is, apply FN pairwise taking as first argument the next
+element of LIST1 and as second argument the next element of LIST2
+at the corresponding position.  The result is as long as the
+shorter list.
+
+This function's anaphoric counterpart is `--zip-with'.
 
-The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it',
-and the elements from LIST2 as symbol `other'."
+For other zips, see also `-zip-lists' and `-zip-fill'."
   (--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.
+  "Zip LISTS together.
 
-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.
+Group the head of each list, followed by the second element of
+each list, and so on.  The number of returned groupings is equal
+to the length of the shortest input list, and the length of each
+grouping is equal to the number of input LISTS.
 
-See also: `-zip'"
+The return value is always a list of proper lists, in contrast to
+`-zip' which returns a list of dotted pairs when only two input
+LISTS are provided.
+
+See also: `-zip-pair'."
   (declare (pure t) (side-effect-free t))
   (when lists
     (let (results)
-      (while (-none? 'null lists)
-        (setq results (cons (mapcar 'car lists) results))
-        (setq lists (mapcar 'cdr lists)))
+      (while (--every it lists)
+        (push (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.
+(defun -zip-lists-fill (fill-value &rest lists)
+  "Zip LISTS together, padding shorter lists with FILL-VALUE.
+This is like `-zip-lists' (which see), except it retains all
+elements at positions beyond the end of the shortest list.  The
+number of returned groupings is equal to the length of the
+longest input list, and the length of each grouping is equal to
+the number of input LISTS."
+  (declare (pure t) (side-effect-free t))
+  (when lists
+    (let (results)
+      (while (--some it lists)
+        (push (--map (if it (car it) fill-value) lists) results)
+        (setq lists (mapcar #'cdr lists)))
+      (nreverse results))))
 
-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.
+(defun -unzip-lists (lists)
+  "Unzip LISTS.
 
-Use `-zip-lists' if you need the return value to always be a list
-of lists.
+This works just like `-zip-lists' (which see), but takes a list
+of lists instead of a variable number of arguments, such that
 
-Alias: `-zip-pair'
+  (-unzip-lists (-zip-lists ARGS...))
 
-See also: `-zip-lists'"
+is identity (given that the lists comprising ARGS are of the same
+length)."
   (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))))
+  (apply #'-zip-lists lists))
+
+(defalias 'dash--length=
+  (if (fboundp 'length=)
+      #'length=
+    (lambda (list length)
+      (cond ((< length 0) nil)
+            ((zerop length) (null list))
+            ((let ((last (nthcdr (1- length) list)))
+               (and last (null (cdr last))))))))
+  "Return non-nil if LIST is of LENGTH.
+This is a compatibility shim for `length=' in Emacs 28.
+\n(fn LIST LENGTH)")
+
+(defun dash--zip-lists-or-pair (_form &rest lists)
+  "Return a form equivalent to applying `-zip' to LISTS.
+This `compiler-macro' warns about discouraged `-zip' usage and
+delegates to `-zip-lists' or `-zip-pair' depending on the number
+of LISTS."
+  (if (not (dash--length= lists 2))
+      (cons #'-zip-lists lists)
+    (let ((pair (cons #'-zip-pair lists))
+          (msg "Use -zip-pair instead of -zip to get a list of pairs"))
+      (if (fboundp 'macroexp-warn-and-return)
+          (macroexp-warn-and-return msg pair)
+        (message msg)
+        pair))))
 
-(defalias '-zip-pair '-zip)
+(defun -zip (&rest lists)
+  "Zip LISTS together.
+
+Group the head of each list, followed by the second element of
+each list, and so on.  The number of returned groupings is equal
+to the length of the shortest input list, and the number of items
+in each grouping is equal to the number of input LISTS.
+
+If only two LISTS are provided as arguments, return the groupings
+as a list of dotted pairs.  Otherwise, return the groupings as a
+list of proper lists.
+
+Since the return value changes form depending on the number of
+arguments, it is generally recommended to use `-zip-lists'
+instead, or `-zip-pair' if a list of dotted pairs is desired.
+
+See also: `-unzip'."
+  (declare (compiler-macro dash--zip-lists-or-pair)
+           (pure t) (side-effect-free t))
+  ;; For backward compatibility, return a list of dotted pairs if two
+  ;; arguments were provided.
+  (apply (if (dash--length= lists 2) #'-zip-pair #'-zip-lists) lists))
+
+(defun -zip-pair (&rest lists)
+  "Zip LIST1 and LIST2 together.
+
+Make a pair with the head of each list, followed by a pair with
+the second element of each list, and so on.  The number of pairs
+returned is equal to the length of the shorter input list.
+
+See also: `-zip-lists'."
+  (declare (advertised-calling-convention (list1 list2) "2.20.0")
+           (pure t) (side-effect-free t))
+  (if (dash--length= lists 2)
+      (--zip-with (cons it other) (car lists) (cadr lists))
+    (apply #'-zip-lists lists)))
 
 (defun -zip-fill (fill-value &rest lists)
-  "Zip LISTS, 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 LISTS together, padding shorter lists with FILL-VALUE.
+This is like `-zip' (which see), except it retains all elements
+at positions beyond the end of the shortest list.  The number of
+returned groupings is equal to the length of the longest input
+list, and the length of each grouping is equal to the number of
+input LISTS.
+
+Since the return value changes form depending on the number of
+arguments, it is generally recommended to use `-zip-lists-fill'
+instead, unless a list of dotted pairs is explicitly desired."
   (declare (pure t) (side-effect-free t))
-  (apply '-zip (apply '-pad (cons fill-value lists))))
+  (cond ((null lists) ())
+        ((dash--length= lists 2)
+         (let ((list1 (car lists))
+               (list2 (cadr lists))
+               results)
+           (while (or list1 list2)
+             (push (cons (if list1 (pop list1) fill-value)
+                         (if list2 (pop list2) fill-value))
+                   results))
+           (nreverse results)))
+        ((apply #'-zip-lists-fill fill-value lists))))
 
 (defun -unzip (lists)
   "Unzip LISTS.
 
-This works just like `-zip' but takes a list of lists instead of
-a variable number of arguments, such that
+This works just like `-zip' (which see), but takes a list of
+lists instead of a variable number of arguments, such that
 
   (-unzip (-zip L1 L2 L3 ...))
 
-is identity (given that the lists are the same length).
+is identity (given that the lists are of the same length, and
+that `-zip' is not called with two arguments, because of the
+caveat described in its docstring).
 
-Note in particular that calling this on a list of two lists will
-return a list of cons-cells such that the above identity works.
+Note in particular that calling `-unzip' on a list of two lists
+will return a list of dotted pairs.
 
-See also: `-zip'"
-  (apply '-zip lists))
+Since the return value changes form depending on the number of
+LISTS, it is generally recommended to use `-unzip-lists' instead."
+  (declare (pure t) (side-effect-free t))
+  (apply #'-zip lists))
 
 (defun -cycle (list)
   "Return an infinite circular copy of LIST.
@@ -2216,7 +2319,7 @@ This method normalizes PATTERN to the format expected by
   (let ((normalized (list (car pattern)))
         (skip nil)
         (fill-placeholder (make-symbol "--dash-fill-placeholder--")))
-    (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern)))
+    (-each (-zip-fill fill-placeholder (cdr pattern) (cddr pattern))
       (lambda (pair)
         (let ((current (car pair))
               (next (cdr pair)))
@@ -2555,7 +2658,8 @@ because we need to support improper list binding."
          ,@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))))
+           (new-varlist (--zip-with (list (car it) (car other))
+                                    varlist inputs)))
       `(let ,inputs
          (-let* ,new-varlist ,@body)))))
 
@@ -3156,7 +3260,7 @@ Return nil if N is less than 1."
 (defun -sum (list)
   "Return the sum of LIST."
   (declare (pure t) (side-effect-free t))
-  (apply '+ list))
+  (apply #'+ list))
 
 (defun -running-sum (list)
   "Return a list with running sums of items in LIST.
@@ -3168,7 +3272,7 @@ LIST must be non-empty."
 (defun -product (list)
   "Return the product of LIST."
   (declare (pure t) (side-effect-free t))
-  (apply '* list))
+  (apply #'* list))
 
 (defun -running-product (list)
   "Return a list with running products of items in LIST.
@@ -3180,12 +3284,12 @@ LIST must be non-empty."
 (defun -max (list)
   "Return the largest value from LIST of numbers or markers."
   (declare (pure t) (side-effect-free t))
-  (apply 'max list))
+  (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))
+  (apply #'min list))
 
 (defun -max-by (comparator list)
   "Take a comparison function COMPARATOR and a LIST and return
@@ -3730,7 +3834,8 @@ This function satisfies the following laws:
     (-compose (-partial #\\='nth n)
               (-prod f1 f2 ...))
   = (-compose fn (-partial #\\='nth n))"
-  (lambda (x) (-zip-with 'funcall fns x)))
+  (declare (pure t) (side-effect-free t))
+  (lambda (x) (--zip-with (funcall it other) fns x)))
 
 ;;; Font lock
 
@@ -3841,7 +3946,6 @@ 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)))
 
@@ -3858,7 +3962,7 @@ additionally fontifies Dash macro calls.
 
 See also `dash-fontify-mode-lighter' and
 `global-dash-fontify-mode'."
-  :group 'dash :lighter dash-fontify-mode-lighter
+  :lighter dash-fontify-mode-lighter
   (if dash-fontify-mode
       (font-lock-add-keywords nil dash--keywords t)
     (font-lock-remove-keywords nil dash--keywords))
@@ -3879,12 +3983,10 @@ See also `dash-fontify-mode-lighter' and
 
 ;;;###autoload
 (define-globalized-minor-mode global-dash-fontify-mode
-  dash-fontify-mode dash--turn-on-fontify-mode
-  :group 'dash)
+  dash-fontify-mode dash--turn-on-fontify-mode)
 
 (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)))
diff --git a/dash.texi b/dash.texi
index 9226c304de..529294c60d 100644
--- a/dash.texi
+++ b/dash.texi
@@ -1120,46 +1120,56 @@ See also: @code{-map-when} (@pxref{-map-when})
 
 @anchor{-remove-at}
 @defun -remove-at (n list)
-Return a list with element at Nth position in @var{list} removed.
+Return @var{list} with its element at index @var{n} removed.
+That is, remove any element selected as (nth @var{n} @var{list}) from 
@var{list}
+and return the result.
 
-See also: @code{-remove-at-indices} (@pxref{-remove-at-indices}), 
@code{-remove} (@pxref{-remove})
+This is a non-destructive operation: parts of @var{list} (but not
+necessarily all of it) are copied as needed to avoid
+destructively modifying it.
+
+See also: @code{-remove-at-indices} (@pxref{-remove-at-indices}), 
@code{-remove} (@pxref{-remove}).
 
 @example
 @group
-(-remove-at 0 '("0" "1" "2" "3" "4" "5"))
-    @result{} ("1" "2" "3" "4" "5")
+(-remove-at 0 '(a b c))
+    @result{} (b c)
 @end group
 @group
-(-remove-at 1 '("0" "1" "2" "3" "4" "5"))
-    @result{} ("0" "2" "3" "4" "5")
+(-remove-at 1 '(a b c))
+    @result{} (a c)
 @end group
 @group
-(-remove-at 2 '("0" "1" "2" "3" "4" "5"))
-    @result{} ("0" "1" "3" "4" "5")
+(-remove-at 2 '(a b c))
+    @result{} (a b)
 @end group
 @end example
 @end defun
 
 @anchor{-remove-at-indices}
 @defun -remove-at-indices (indices list)
-Return a list whose elements are elements from @var{list} without
-elements selected as `(nth i list)` for all i
-from @var{indices}.
+Return @var{list} with its elements at @var{indices} removed.
+That is, for each index @var{i} in @var{indices}, remove any element selected
+as (nth @var{i} @var{list}) from @var{list}.
+
+This is a non-destructive operation: parts of @var{list} (but not
+necessarily all of it) are copied as needed to avoid
+destructively modifying it.
 
-See also: @code{-remove-at} (@pxref{-remove-at}), @code{-remove} 
(@pxref{-remove})
+See also: @code{-remove-at} (@pxref{-remove-at}), @code{-remove} 
(@pxref{-remove}).
 
 @example
 @group
-(-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5"))
-    @result{} ("1" "2" "3" "4" "5")
+(-remove-at-indices '(0) '(a b c d e))
+    @result{} (b c d e)
 @end group
 @group
-(-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5"))
-    @result{} ("1" "3" "5")
+(-remove-at-indices '(1 3) '(a b c d e))
+    @result{} (a c e)
 @end group
 @group
-(-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5"))
-    @result{} ("1" "2" "3" "4")
+(-remove-at-indices '(4 0 2) '(a b c d e))
+    @result{} (b d)
 @end group
 @end example
 @end defun
@@ -1795,8 +1805,8 @@ from the beginning.
     @result{} (1 "and" 3 1 "and" 3 1)
 @end group
 @group
-(-zip (-cycle '(1 2 3)) '(1 2))
-    @result{} ((1 . 1) (2 . 2))
+(-zip-lists (-cycle '(3)) '(1 2))
+    @result{} ((3 1) (3 2))
 @end group
 @end example
 @end defun
@@ -2923,73 +2933,72 @@ the @var{apl} language.
 
 @anchor{-zip-with}
 @defun -zip-with (fn list1 list2)
-Zip the two lists @var{list1} and @var{list2} using a function @var{fn}.  This
-function is applied pairwise taking as first argument element of
-@var{list1} and as second argument element of @var{list2} at corresponding
-position.
+Zip @var{list1} and @var{list2} into a new list using the function @var{fn}.
+That is, apply @var{fn} pairwise taking as first argument the next
+element of @var{list1} and as second argument the next element of @var{list2}
+at the corresponding position.  The result is as long as the
+shorter list.
 
-The anaphoric form @code{--zip-with} binds the elements from @var{list1} as 
symbol @code{it},
-and the elements from @var{list2} as symbol @code{other}.
+This function's anaphoric counterpart is @code{--zip-with}.
+
+For other zips, see also @code{-zip-lists} (@pxref{-zip-lists}) and 
@code{-zip-fill} (@pxref{-zip-fill}).
 
 @example
 @group
-(-zip-with '+ '(1 2 3) '(4 5 6))
-    @result{} (5 7 9)
+(-zip-with #'+ '(1 2 3 4) '(5 6 7))
+    @result{} (6 8 10)
 @end group
 @group
-(-zip-with 'cons '(1 2 3) '(4 5 6))
+(-zip-with #'cons '(1 2 3) '(4 5 6 7))
     @result{} ((1 . 4) (2 . 5) (3 . 6))
 @end group
 @group
-(--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde"))
-    @result{} ("Batman and Robin" "Jekyll and Hyde")
+(--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde))
+    @result{} ("Batman & Robin" "Jekyll & Hyde")
 @end group
 @end example
 @end defun
 
-@anchor{-zip}
-@defun -zip (&rest lists)
-Zip @var{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.
+@anchor{-zip-pair}
+@defun -zip-pair (list1 list2)
+Zip @var{list1} and @var{list2} together.
 
-Use @code{-zip-lists} (@pxref{-zip-lists}) if you need the return value to 
always be a list
-of lists.
+Make a pair with the head of each list, followed by a pair with
+the second element of each list, and so on.  The number of pairs
+returned is equal to the length of the shorter input list.
 
-Alias: @code{-zip-pair}
-
-See also: @code{-zip-lists} (@pxref{-zip-lists})
+See also: @code{-zip-lists} (@pxref{-zip-lists}).
 
 @example
 @group
-(-zip '(1 2 3) '(4 5 6))
-    @result{} ((1 . 4) (2 . 5) (3 . 6))
+(-zip-pair '(1 2 3 4) '(5 6 7))
+    @result{} ((1 . 5) (2 . 6) (3 . 7))
 @end group
 @group
-(-zip '(1 2 3) '(4 5 6 7))
+(-zip-pair '(1 2 3) '(4 5 6))
     @result{} ((1 . 4) (2 . 5) (3 . 6))
 @end group
 @group
-(-zip '(1 2) '(3 4 5) '(6))
-    @result{} ((1 3 6))
+(-zip-pair '(1 2) '(3))
+    @result{} ((1 . 3))
 @end group
 @end example
 @end defun
 
 @anchor{-zip-lists}
 @defun -zip-lists (&rest lists)
-Zip @var{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.
+Zip @var{lists} together.
+
+Group the head of each list, followed by the second element of
+each list, and so on.  The number of returned groupings is equal
+to the length of the shortest input list, and the length of each
+grouping is equal to the number of input @var{lists}.
 
-The return value is always list of lists, which is a difference
-from @code{-zip-pair} which returns a cons-cell in case two input
-lists are provided.
+The return value is always a list of proper lists, in contrast to
+@code{-zip} (@pxref{-zip}) which returns a list of dotted pairs when only two 
input
+@var{lists} are provided.
 
-See also: @code{-zip} (@pxref{-zip})
+See also: @code{-zip-pair} (@pxref{-zip-pair}).
 
 @example
 @group
@@ -3007,16 +3016,119 @@ See also: @code{-zip} (@pxref{-zip})
 @end example
 @end defun
 
+@anchor{-zip-lists-fill}
+@defun -zip-lists-fill (fill-value &rest lists)
+Zip @var{lists} together, padding shorter lists with @var{fill-value}.
+This is like @code{-zip-lists} (@pxref{-zip-lists}) (which see), except it 
retains all
+elements at positions beyond the end of the shortest list.  The
+number of returned groupings is equal to the length of the
+longest input list, and the length of each grouping is equal to
+the number of input @var{lists}.
+
+@example
+@group
+(-zip-lists-fill 0 '(1 2) '(3 4 5) '(6))
+    @result{} ((1 3 6) (2 4 0) (0 5 0))
+@end group
+@group
+(-zip-lists-fill 0 '(1 2) '(3 4) '(5 6))
+    @result{} ((1 3 5) (2 4 6))
+@end group
+@group
+(-zip-lists-fill 0 '(1 2 3) nil)
+    @result{} ((1 0) (2 0) (3 0))
+@end group
+@end example
+@end defun
+
+@anchor{-zip}
+@defun -zip (&rest lists)
+Zip @var{lists} together.
+
+Group the head of each list, followed by the second element of
+each list, and so on.  The number of returned groupings is equal
+to the length of the shortest input list, and the number of items
+in each grouping is equal to the number of input @var{lists}.
+
+If only two @var{lists} are provided as arguments, return the groupings
+as a list of dotted pairs.  Otherwise, return the groupings as a
+list of proper lists.
+
+Since the return value changes form depending on the number of
+arguments, it is generally recommended to use @code{-zip-lists} 
(@pxref{-zip-lists})
+instead, or @code{-zip-pair} (@pxref{-zip-pair}) if a list of dotted pairs is 
desired.
+
+See also: @code{-unzip} (@pxref{-unzip}).
+
+@example
+@group
+(-zip '(1 2 3 4) '(5 6 7) '(8 9))
+    @result{} ((1 5 8) (2 6 9))
+@end group
+@group
+(-zip '(1 2 3) '(4 5 6) '(7 8 9))
+    @result{} ((1 4 7) (2 5 8) (3 6 9))
+@end group
+@group
+(-zip '(1 2 3))
+    @result{} ((1) (2) (3))
+@end group
+@end example
+@end defun
+
 @anchor{-zip-fill}
 @defun -zip-fill (fill-value &rest lists)
-Zip @var{lists}, with @var{fill-value} padded onto the shorter lists. The
-lengths of the returned groupings are equal to the length of the
-longest input list.
+Zip @var{lists} together, padding shorter lists with @var{fill-value}.
+This is like @code{-zip} (@pxref{-zip}) (which see), except it retains all 
elements
+at positions beyond the end of the shortest list.  The number of
+returned groupings is equal to the length of the longest input
+list, and the length of each grouping is equal to the number of
+input @var{lists}.
+
+Since the return value changes form depending on the number of
+arguments, it is generally recommended to use @code{-zip-lists-fill} 
(@pxref{-zip-lists-fill})
+instead, unless a list of dotted pairs is explicitly desired.
 
 @example
 @group
-(-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9))
-    @result{} ((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0))
+(-zip-fill 0 '(1 2 3) '(4 5))
+    @result{} ((1 . 4) (2 . 5) (3 . 0))
+@end group
+@group
+(-zip-fill 0 () '(1 2 3))
+    @result{} ((0 . 1) (0 . 2) (0 . 3))
+@end group
+@group
+(-zip-fill 0 '(1 2) '(3 4) '(5 6))
+    @result{} ((1 3 5) (2 4 6))
+@end group
+@end example
+@end defun
+
+@anchor{-unzip-lists}
+@defun -unzip-lists (lists)
+Unzip @var{lists}.
+
+This works just like @code{-zip-lists} (@pxref{-zip-lists}) (which see), but 
takes a list
+of lists instead of a variable number of arguments, such that
+
+  (-unzip-lists (-zip-lists @var{args}@dots{}))
+
+is identity (given that the lists comprising @var{args} are of the same
+length).
+
+@example
+@group
+(-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6)))
+    @result{} ((1 2) (3 4) (5 6))
+@end group
+@group
+(-unzip-lists '((1 2 3) (4 5) (6 7) (8 9)))
+    @result{} ((1 4 6 8) (2 5 7 9))
+@end group
+@group
+(-unzip-lists '((1 2 3) (4 5 6)))
+    @result{} ((1 4) (2 5) (3 6))
 @end group
 @end example
 @end defun
@@ -3025,30 +3137,33 @@ longest input list.
 @defun -unzip (lists)
 Unzip @var{lists}.
 
-This works just like @code{-zip} (@pxref{-zip}) but takes a list of lists 
instead of
-a variable number of arguments, such that
+This works just like @code{-zip} (@pxref{-zip}) (which see), but takes a list 
of
+lists instead of a variable number of arguments, such that
 
   (-unzip (-zip @var{l1} @var{l2} @var{l3} @dots{}))
 
-is identity (given that the lists are the same length).
+is identity (given that the lists are of the same length, and
+that @code{-zip} (@pxref{-zip}) is not called with two arguments, because of 
the
+caveat described in its docstring).
 
-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.
+Note in particular that calling @code{-unzip} (@pxref{-unzip}) on a list of 
two lists
+will return a list of dotted pairs.
 
-See also: @code{-zip} (@pxref{-zip})
+Since the return value changes form depending on the number of
+@var{lists}, it is generally recommended to use @code{-unzip-lists} 
(@pxref{-unzip-lists}) instead.
 
 @example
 @group
-(-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g")))
-    @result{} ((1 2 3) (a b c) ("e" "f" "g"))
+(-unzip (-zip '(1 2) '(3 4) '(5 6)))
+    @result{} ((1 . 2) (3 . 4) (5 . 6))
 @end group
 @group
-(-unzip '((1 2) (3 4) (5 6) (7 8) (9 10)))
-    @result{} ((1 3 5 7 9) (2 4 6 8 10))
+(-unzip '((1 2 3) (4 5 6)))
+    @result{} ((1 . 4) (2 . 5) (3 . 6))
 @end group
 @group
-(-unzip '((1 2) (3 4)))
-    @result{} ((1 . 3) (2 . 4))
+(-unzip '((1 2 3) (4 5) (6 7) (8 9)))
+    @result{} ((1 4 6 8) (2 5 7 9))
 @end group
 @end example
 @end defun
@@ -4792,16 +4907,16 @@ This function satisfies the following laws:
 
 @example
 @group
-(funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3))
+(funcall (-prodfn #'1+ #'1- #'number-to-string) '(1 2 3))
     @result{} (2 1 "3")
 @end group
 @group
-(-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8)))
-    @result{} ((2 1) (4 3) (6 5) (8 7))
+(-map (-prodfn #'1- #'1+) '((1 2) (3 4) (5 6)))
+    @result{} ((0 3) (2 5) (4 7))
 @end group
 @group
-(apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15")))
-    @result{} 18
+(apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5")))
+    @result{} 6
 @end group
 @end example
 @end defun
diff --git a/dev/examples.el b/dev/examples.el
index 33cef8bb58..aca7c69cea 100644
--- a/dev/examples.el
+++ b/dev/examples.el
@@ -466,34 +466,145 @@ new list."
     (--update-at 2 (concat it "zab") '("foo" "bar" "baz" "quux")) => '("foo" 
"bar" "bazzab" "quux"))
 
   (defexamples -remove-at
-    (-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")
-    (-remove-at 3 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "4" "5")
-    (-remove-at 4 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" "5")
-    (-remove-at 5 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" "4")
-    (-remove-at 5 '((a b) (c d) (e f g) h i ((j) k) l (m))) => '((a b) (c d) 
(e f g) h i l (m))
-    (-remove-at 0 '(((a b) (c d) (e f g) h i ((j) k) l (m)))) => nil)
+    (-remove-at 0 '(a b c)) => '(b c)
+    (-remove-at 1 '(a b c)) => '(a c)
+    (-remove-at 2 '(a b c)) => '(a b)
+    (-remove-at -1 ()) => ()
+    (-remove-at 0 ()) => ()
+    (-remove-at 1 ()) => ()
+    (-remove-at -1 '(a)) => '(a)
+    (-remove-at 0 '(a)) => ()
+    (-remove-at 1 '(a)) => '(a)
+    (-remove-at -1 '(a b)) => '(a b)
+    (-remove-at 0 '(a b)) => '(b)
+    (-remove-at 1 '(a b)) => '(a)
+    (-remove-at 2 '(a b)) => '(a b)
+    (-remove-at 0 '((a))) => ()
+    (-remove-at 2 '((a) b (c . d) e)) => '((a) b e)
+    ;; Test for destructive modification.
+    (let ((l (list 0))) (ignore (-remove-at -1 l)) l) => '(0)
+    (let ((l (list 0))) (ignore (-remove-at 0 l)) l) => '(0)
+    (let ((l (list 0))) (ignore (-remove-at 1 l)) l) => '(0)
+    (let ((l (list 0 1))) (ignore (-remove-at -1 l)) l) => '(0 1)
+    (let ((l (list 0 1))) (ignore (-remove-at 0 l)) l) => '(0 1)
+    (let ((l (list 0 1))) (ignore (-remove-at 1 l)) l) => '(0 1)
+    (let ((l (list 0 1))) (ignore (-remove-at 2 l)) l) => '(0 1))
 
   (defexamples -remove-at-indices
-    (-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")
-    (-remove-at-indices '(1 2 3) '("0" "1" "2" "3" "4" "5")) => '("0" "4" "5")
-    (-remove-at-indices '(0 1 2 3 4 5) '("0" "1" "2" "3" "4" "5")) => nil
-    (-remove-at-indices '(2 0 4) '("0" "1" "2" "3" "4" "5")) => '("1" "3" "5")
-    (-remove-at-indices '(5 0) '("0" "1" "2" "3" "4" "5")) => '("1" "2" "3" 
"4")
-    (-remove-at-indices '(1 3 2) '("0" "1" "2" "3" "4" "5")) => '("0" "4" "5")
-    (-remove-at-indices '(0 3 4 2 5 1) '("0" "1" "2" "3" "4" "5")) => nil
-    (-remove-at-indices '(1) '("0" "1" "2" "3" "4" "5")) => '("0" "2" "3" "4" 
"5")
-    (-remove-at-indices '(2) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "3" "4" 
"5")
-    (-remove-at-indices '(3) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "4" 
"5")
-    (-remove-at-indices '(4) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" 
"5")
-    (-remove-at-indices '(5) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" 
"4")
-    (-remove-at-indices '(1 2 4) '((a b) (c d) (e f g) h i ((j) k) l (m))) => 
'((a b) h ((j) k) l (m))
-    (-remove-at-indices '(5) '((a b) (c d) (e f g) h i ((j) k) l (m))) => '((a 
b) (c d) (e f g) h i l (m))
-    (-remove-at-indices '(0) '(((a b) (c d) (e f g) h i ((j) k) l (m)))) => nil
-    (-remove-at-indices '(2 3) '((0) (1) (2) (3) (4) (5) (6))) => '((0) (1) 
(4) (5) (6))))
+    (-remove-at-indices '(0) '(a b c d e)) => '(b c d e)
+    (-remove-at-indices '(1 3) '(a b c d e)) => '(a c e)
+    (-remove-at-indices '(4 0 2) '(a b c d e)) => '(b d)
+    (-remove-at-indices () ()) => ()
+    (-remove-at-indices '(-1) ()) => ()
+    (-remove-at-indices '(0) ()) => ()
+    (-remove-at-indices '(-1 0) ()) => ()
+    (-remove-at-indices '(0 -1) ()) => ()
+    (-remove-at-indices '(-1 -1) ()) => ()
+    (-remove-at-indices '(0 0) ()) => ()
+    (-remove-at-indices () '(a)) => '(a)
+    (-remove-at-indices '(-1) '(a)) => '(a)
+    (-remove-at-indices '(0) '(a)) => ()
+    (-remove-at-indices '(1) '(a)) => '(a)
+    (-remove-at-indices '(-1 -1) '(a)) => '(a)
+    (-remove-at-indices '(-1 0) '(a)) => ()
+    (-remove-at-indices '(0 -1) '(a)) => ()
+    (-remove-at-indices '(-1 1) '(a)) => '(a)
+    (-remove-at-indices '(1 -1) '(a)) => '(a)
+    (-remove-at-indices '(0 0) '(a)) => ()
+    (-remove-at-indices '(0 1) '(a)) => ()
+    (-remove-at-indices '(1 0) '(a)) => ()
+    (-remove-at-indices '(1 1) '(a)) => '(a)
+    (-remove-at-indices () '(a b)) => '(a b)
+    (-remove-at-indices '(-1) '(a b)) => '(a b)
+    (-remove-at-indices '(0) '(a b)) => '(b)
+    (-remove-at-indices '(1) '(a b)) => '(a)
+    (-remove-at-indices '(2) '(a b)) => '(a b)
+    (-remove-at-indices '(-2 -1) '(a b)) => '(a b)
+    (-remove-at-indices '(-1 -1) '(a b)) => '(a b)
+    (-remove-at-indices '(-1 0) '(a b)) => '(b)
+    (-remove-at-indices '(0 -1) '(a b)) => '(b)
+    (-remove-at-indices '(-1 1) '(a b)) => '(a)
+    (-remove-at-indices '(1 -1) '(a b)) => '(a)
+    (-remove-at-indices '(-1 2) '(a b)) => '(a b)
+    (-remove-at-indices '(2 -1) '(a b)) => '(a b)
+    (-remove-at-indices '(0 0) '(a b)) => '(b)
+    (-remove-at-indices '(0 1) '(a b)) => ()
+    (-remove-at-indices '(1 0) '(a b)) => ()
+    (-remove-at-indices '(0 2) '(a b)) => '(b)
+    (-remove-at-indices '(2 0) '(a b)) => '(b)
+    (-remove-at-indices '(1 1) '(a b)) => '(a)
+    (-remove-at-indices '(1 2) '(a b)) => '(a)
+    (-remove-at-indices '(2 1) '(a b)) => '(a)
+    (-remove-at-indices '(2 2) '(a b)) => '(a b)
+    (-remove-at-indices '(-1 0 0) '(a b)) => '(b)
+    (-remove-at-indices '(-1 0 1) '(a b)) => ()
+    (-remove-at-indices '(-1 1 1) '(a b)) => '(a)
+    (-remove-at-indices '(1 -1 0) '(a b)) => ()
+    (-remove-at-indices '(-1 -2 -3) '(a b)) => '(a b)
+    (-remove-at-indices '(4 3 2) '(a b)) => '(a b)
+    (-remove-at-indices '(0 0 0) '(a b)) => '(b)
+    (-remove-at-indices '(1 1 1) '(a b)) => '(a)
+    (-remove-at-indices () '(a b c)) => '(a b c)
+    (-remove-at-indices '(-1) '(a b c)) => '(a b c)
+    (-remove-at-indices '(3) '(a b c)) => '(a b c)
+    (-remove-at-indices '(-1 -1) '(a b c)) => '(a b c)
+    (-remove-at-indices '(-1 0) '(a b c)) => '(b c)
+    (-remove-at-indices '(0 -1) '(a b c)) => '(b c)
+    (-remove-at-indices '(-1 1) '(a b c)) => '(a c)
+    (-remove-at-indices '(1 -1) '(a b c)) => '(a c)
+    (-remove-at-indices '(-1 2) '(a b c)) => '(a b)
+    (-remove-at-indices '(2 -1) '(a b c)) => '(a b)
+    (-remove-at-indices '(-1 3) '(a b c)) => '(a b c)
+    (-remove-at-indices '(3 -1) '(a b c)) => '(a b c)
+    (-remove-at-indices '(-1 -2) '(a b c)) => '(a b c)
+    (-remove-at-indices '(3 3) '(a b c)) => '(a b c)
+    (-remove-at-indices '(4 3) '(a b c)) => '(a b c)
+    (-remove-at-indices '(2 -1 0) '(a b c)) => '(b)
+    (-remove-at-indices '(3 -1 2 1) '(a b c)) => '(a)
+    (-remove-at-indices '(3 0 -1 1) '(a b c)) => '(c)
+    (-remove-at-indices '(2 2 0 0) '(a b c)) => '(b)
+    (-remove-at-indices '(0 0 2) '(a b c)) => '(b)
+    (-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)
+    (-remove-at-indices '(1 2 3) '(0 1 2 3 4 5)) => '(0 4 5)
+    (-remove-at-indices '(0 1 2 3 4 5) '(0 1 2 3 4 5)) => ()
+    (-remove-at-indices '(2 0 4) '(0 1 2 3 4 5)) => '(1 3 5)
+    (-remove-at-indices '(5 0) '(0 1 2 3 4 5)) => '(1 2 3 4)
+    (-remove-at-indices '(1 3 2) '(0 1 2 3 4 5)) => '(0 4 5)
+    (-remove-at-indices '(0 3 4 2 5 1) '(0 1 2 3 4 5)) => ()
+    (-remove-at-indices '(1) '(0 1 2 3 4 5)) => '(0 2 3 4 5)
+    (-remove-at-indices '(2) '(0 1 2 3 4 5)) => '(0 1 3 4 5)
+    (-remove-at-indices '(3) '(0 1 2 3 4 5)) => '(0 1 2 4 5)
+    (-remove-at-indices '(4) '(0 1 2 3 4 5)) => '(0 1 2 3 5)
+    (-remove-at-indices '(5) '(0 1 2 3 4 5)) => '(0 1 2 3 4)
+    (-remove-at-indices '(1 2 4) '((a b) (c d) (e f g) h i ((j) k) l (m)))
+    => '((a b) h ((j) k) l (m))
+    (-remove-at-indices '(5) '((a b) (c d) (e f g) h i ((j) k) l (m)))
+    => '((a b) (c d) (e f g) h i l (m))
+    (-remove-at-indices '(0) '(((a b) (c d) (e f g) h i ((j) k) l (m)))) => ()
+    (-remove-at-indices '(2 3) '((0) (1) (2) (3) (4) (5) (6)))
+    => '((0) (1) (4) (5) (6))
+    ;; Test for destructive modification.
+    (let ((l (list 0))) (ignore (-remove-at-indices '(0) l)) l) => '(0)
+    (let ((l (list 0 1))) (ignore (-remove-at-indices '(0) l)) l) => '(0 1)
+    (let ((l (list 0 1))) (ignore (-remove-at-indices '(1) l)) l) => '(0 1)
+    (let ((l (list 0 1))) (ignore (-remove-at-indices '(0 1) l)) l) => '(0 1)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0) l)) l) => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(1) l)) l) => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(2) l)) l) => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0 0) l)) l)
+    => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0 1) l)) l)
+    => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0 2) l)) l)
+    => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(1 1) l)) l)
+    => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(1 2) l)) l)
+    => '(0 1 2)
+    (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(2 2) l)) l)
+    => '(0 1 2)))
 
 (def-example-group "Reductions"
   "Functions reducing lists to a single value (which may also be a list)."
@@ -736,9 +847,10 @@ value rather than consuming a list to produce a single 
value."
   (defexamples -cycle
     (-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))
-    (-zip-with #'cons (-cycle '(1 2 3)) '(1 2)) => '((1 . 1) (2 . 2))
-    (-map (-partial #'-take 5) (-split-at 5 (-cycle '(1 2 3)))) => '((1 2 3 1 
2) (3 1 2 3 1))
+    (-zip-lists (-cycle '(3)) '(1 2)) => '((3 1) (3 2))
+    (-zip-with #'cons (-cycle '(3)) '(1 2)) => '((3 . 1) (3 . 2))
+    (--map (-take 5 it) (-split-at 5 (-cycle '(1 2 3))))
+    => '((1 2 3 1 2) (3 1 2 3 1))
     (let ((l (list 1))) (eq l (-cycle l))) => nil))
 
 (def-example-group "Predicates"
@@ -1468,17 +1580,60 @@ related predicates."
     (-iota 1 nil -1) => '(0))
 
   (defexamples -zip-with
-    (-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"))
-
-  (defexamples -zip
-    (-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))
-    (-zip '(1 2 3 4) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6))
-    (-zip '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9))
-    (-zip) => nil)
+    (-zip-with #'+ '(1 2 3 4) '(5 6 7)) => '(6 8 10)
+    (-zip-with #'cons '(1 2 3) '(4 5 6 7)) => '((1 . 4) (2 . 5) (3 . 6))
+    (--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde))
+    => '("Batman & Robin" "Jekyll & Hyde")
+    (-zip-with #'cons '(nil) '(nil)) => '((nil))
+    (-zip-with #'cons '(nil) '(nil nil)) => '((nil))
+    (-zip-with #'cons '(nil nil) '(nil)) => '((nil))
+    (-zip-with #'cons '(nil nil) '(nil nil)) => '((nil) (nil))
+    (--zip-with (cons it other) () ()) => ()
+    (--zip-with (cons it other) () '(nil)) => ()
+    (--zip-with (cons it other) '(nil) '()) => ()
+    (--zip-with (cons it other) '(nil) '(nil)) => '((nil))
+    (--zip-with (cons it other) '(nil) '(nil nil)) => '((nil))
+    (--zip-with (cons it other) '(nil nil) '(nil)) => '((nil))
+    (--zip-with (cons it other) '(nil nil) '(nil nil)) => '((nil) (nil))
+    (-zip-with #'signal () ()) => ()
+    (-zip-with #'signal '(arith-error) ()) => ()
+    (-zip-with #'signal () '(())) => ()
+    (-zip-with #'signal '(arith-error) '(())) !!> (arith-error))
+
+  (defexamples -zip-pair
+    (-zip-pair '(1 2 3 4) '(5 6 7)) => '((1 . 5) (2 . 6) (3 . 7))
+    (-zip-pair '(1 2 3) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6))
+    (-zip-pair '(1 2) '(3)) => '((1 . 3))
+    (-zip-pair () ()) => ()
+    (-zip-pair '(0) ()) => ()
+    (-zip-pair () '(0)) => ()
+    (-zip-pair '(1 2 3 4) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6))
+    (-zip-pair '(1 2 3) '(4 5 6 7)) => '((1 . 4) (2 . 5) (3 . 6))
+    (with-no-warnings (-zip-pair '(1 2 3 4) '(5 6 7) '(8 9)))
+    => '((1 5 8) (2 6 9))
+    (with-no-warnings (-zip-pair '(1 2 3) '(4 5 6) '(7 8 9)))
+    => '((1 4 7) (2 5 8) (3 6 9))
+    (with-no-warnings (-zip-pair '(1 2 3))) => '((1) (2) (3))
+    (with-no-warnings (-zip-pair)) => ()
+    (with-no-warnings (-zip-pair ())) => ()
+    (with-no-warnings (-zip-pair '(0))) => '((0))
+    (with-no-warnings (-zip-pair '(0 1))) => '((0) (1))
+    (with-no-warnings (-zip-pair () () ())) => ()
+    (with-no-warnings (-zip-pair '(0) () ())) => ()
+    (with-no-warnings (-zip-pair () '(0) ())) => ()
+    (with-no-warnings (-zip-pair () () '(0))) => ()
+    (with-no-warnings (-zip-pair '(0) '(1) ())) => ()
+    (with-no-warnings (-zip-pair '(0) () '(1))) => ()
+    (with-no-warnings (-zip-pair () '(0) '(1))) => ()
+    (with-no-warnings (-zip-pair '(0) '(1) '(2))) => '((0 1 2))
+    (with-no-warnings (-zip-pair '(0 1) '(2) '(3))) => '((0 2 3))
+    (with-no-warnings (-zip-pair '(0) '(1 2) '(3))) => '((0 1 3))
+    (with-no-warnings (-zip-pair '(0) '(1) '(2 3))) => '((0 1 2))
+    (with-no-warnings (-zip-pair '(0 1) '(2 3) '(4))) => '((0 2 4))
+    (with-no-warnings (-zip-pair '(0 1) '(2) '(3 4))) => '((0 2 3))
+    (with-no-warnings (-zip-pair '(0) '(1 2) '(3 4))) => '((0 1 3))
+    (with-no-warnings (-zip-pair '(0 1) '(2 3) '(4 5))) => '((0 2 4) (1 3 5))
+    (with-no-warnings (-zip-pair '(0 1) '(2 3 4) '(5))) => '((0 2 5)))
 
   (defexamples -zip-lists
     (-zip-lists '(1 2 3) '(4 5 6)) => '((1 4) (2 5) (3 6))
@@ -1486,15 +1641,173 @@ related predicates."
     (-zip-lists '(1 2) '(3 4 5) '(6)) => '((1 3 6))
     (-zip-lists '(1 2 3 4) '(4 5 6)) => '((1 4) (2 5) (3 6))
     (-zip-lists '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9))
-    (-zip-lists) => nil)
+    (-zip-lists) => ()
+    (-zip-lists ()) => ()
+    (-zip-lists '(0)) => '((0))
+    (-zip-lists '(0 1)) => '((0) (1))
+    (-zip-lists '(0 1 2)) => '((0) (1) (2))
+    (-zip-lists () ()) => ()
+    (-zip-lists '(0) ()) => ()
+    (-zip-lists () '(0)) => ()
+    (-zip-lists () () ()) => ()
+    (-zip-lists '(0) () ()) => ()
+    (-zip-lists () '(0) ()) => ()
+    (-zip-lists () () '(0)) => ()
+    (-zip-lists '(0) '(1) ()) => ()
+    (-zip-lists '(0) () '(1)) => ()
+    (-zip-lists () '(0) '(1)) => ()
+    (-zip-lists '(0) '(1) '(2)) => '((0 1 2))
+    (-zip-lists '(0 1) '(2) '(3)) => '((0 2 3))
+    (-zip-lists '(0) '(1 2) '(3)) => '((0 1 3))
+    (-zip-lists '(0) '(1) '(2 3)) => '((0 1 2))
+    (-zip-lists '(0 1) '(2 3) '(4)) => '((0 2 4))
+    (-zip-lists '(0 1) '(2) '(3 4)) => '((0 2 3))
+    (-zip-lists '(0) '(1 2) '(3 4)) => '((0 1 3))
+    (-zip-lists '(0 1) '(2 3) '(4 5)) => '((0 2 4) (1 3 5)))
+
+  (defexamples -zip-lists-fill
+    (-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) => '((1 3 6) (2 4 0) (0 5 0))
+    (-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) => '((1 3 5) (2 4 6))
+    (-zip-lists-fill 0 '(1 2 3) ()) => '((1 0) (2 0) (3 0))
+    (-zip-lists-fill 0) => ()
+    (-zip-lists-fill 0 ()) => ()
+    (-zip-lists-fill 0 '(1)) => '((1))
+    (-zip-lists-fill 0 '(1 2)) => '((1) (2))
+    (-zip-lists-fill 0 '(1 2 3)) => '((1) (2) (3))
+    (-zip-lists-fill 0 () ()) => ()
+    (-zip-lists-fill 0 '(1) ()) => '((1 0))
+    (-zip-lists-fill 0 () '(1)) => '((0 1))
+    (-zip-lists-fill 0 '(1) '(2)) => '((1 2))
+    (-zip-lists-fill 0 '(1 2) ()) => '((1 0) (2 0))
+    (-zip-lists-fill 0 () '(1 2)) => '((0 1) (0 2))
+    (-zip-lists-fill 0 () '(1 2 3)) => '((0 1) (0 2) (0 3))
+    (-zip-lists-fill 0 '(1 2) '(3)) => '((1 3) (2 0))
+    (-zip-lists-fill 0 '(1) '(2 3)) => '((1 2) (0 3))
+    (-zip-lists-fill 0 () () ()) => ()
+    (-zip-lists-fill 0 '(1) () ()) => '((1 0 0))
+    (-zip-lists-fill 0 () '(1) ()) => '((0 1 0))
+    (-zip-lists-fill 0 () () '(1)) => '((0 0 1))
+    (-zip-lists-fill 0 '(1 2) () ()) => '((1 0 0) (2 0 0))
+    (-zip-lists-fill 0 () '(1 2) ()) => '((0 1 0) (0 2 0))
+    (-zip-lists-fill 0 () () '(1 2)) => '((0 0 1) (0 0 2)))
+
+  (defexamples -zip
+    (-zip '(1 2 3 4) '(5 6 7) '(8 9)) => '((1 5 8) (2 6 9))
+    (-zip '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9))
+    (-zip '(1 2 3)) => '((1) (2) (3))
+    (-zip) => ()
+    (-zip ()) => ()
+    (-zip '(0)) => '((0))
+    (-zip '(0 1)) => '((0) (1))
+    (with-no-warnings (-zip () ())) => ()
+    (with-no-warnings (-zip '(0) ())) => ()
+    (with-no-warnings (-zip () '(0))) => ()
+    (with-no-warnings (-zip '(1 2 3 4) '(4 5 6))) => '((1 . 4) (2 . 5) (3 . 6))
+    (with-no-warnings (-zip '(1 2 3) '(4 5 6 7))) => '((1 . 4) (2 . 5) (3 . 6))
+    (-zip () () ()) => ()
+    (-zip '(0) () ()) => ()
+    (-zip () '(0) ()) => ()
+    (-zip () () '(0)) => ()
+    (-zip '(0) '(1) ()) => ()
+    (-zip '(0) () '(1)) => ()
+    (-zip () '(0) '(1)) => ()
+    (-zip '(0) '(1) '(2)) => '((0 1 2))
+    (-zip '(0 1) '(2) '(3)) => '((0 2 3))
+    (-zip '(0) '(1 2) '(3)) => '((0 1 3))
+    (-zip '(0) '(1) '(2 3)) => '((0 1 2))
+    (-zip '(0 1) '(2 3) '(4)) => '((0 2 4))
+    (-zip '(0 1) '(2) '(3 4)) => '((0 2 3))
+    (-zip '(0) '(1 2) '(3 4)) => '((0 1 3))
+    (-zip '(0 1) '(2 3) '(4 5)) => '((0 2 4) (1 3 5))
+    (-zip '(0 1) '(2 3 4) '(5)) => '((0 2 5)))
 
   (defexamples -zip-fill
-    (-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) => '((1 . 6) (2 . 7) (3 . 8) (4 . 9) 
(5 . 0)))
+    (-zip-fill 0 '(1 2 3) '(4 5)) => '((1 . 4) (2 . 5) (3 . 0))
+    (-zip-fill 0 '() '(1 2 3)) => '((0 . 1) (0 . 2) (0 . 3))
+    (-zip-fill 0 '(1 2) '(3 4) '(5 6)) => '((1 3 5) (2 4 6))
+    (-zip-fill 0 '(1 2) '(3 4 5) '(6)) => '((1 3 6) (2 4 0) (0 5 0))
+    (-zip-fill 0) => ()
+    (-zip-fill 0 ()) => ()
+    (-zip-fill 0 '(1)) => '((1))
+    (-zip-fill 0 '(1 2)) => '((1) (2))
+    (-zip-fill 0 '(1 2 3)) => '((1) (2) (3))
+    (-zip-fill 0 () ()) => ()
+    (-zip-fill 0 '(1) ()) => '((1 . 0))
+    (-zip-fill 0 () '(1)) => '((0 . 1))
+    (-zip-fill 0 '(1) '(2)) => '((1 . 2))
+    (-zip-fill 0 '(1 2) ()) => '((1 . 0) (2 . 0))
+    (-zip-fill 0 () '(1 2)) => '((0 . 1) (0 . 2))
+    (-zip-fill 0 '(1 2 3) ()) => '((1 . 0) (2 . 0) (3 . 0))
+    (-zip-fill 0 () '(1 2 3)) => '((0 . 1) (0 . 2) (0 . 3))
+    (-zip-fill 0 '(1 2) '(3)) => '((1 . 3) (2 . 0))
+    (-zip-fill 0 '(1) '(2 3)) => '((1 . 2) (0 . 3))
+    (-zip-fill 0 () () ()) => ()
+    (-zip-fill 0 '(1) () ()) => '((1 0 0))
+    (-zip-fill 0 () '(1) ()) => '((0 1 0))
+    (-zip-fill 0 () () '(1)) => '((0 0 1))
+    (-zip-fill 0 '(1 2) () ()) => '((1 0 0) (2 0 0))
+    (-zip-fill 0 () '(1 2) ()) => '((0 1 0) (0 2 0))
+    (-zip-fill 0 () () '(1 2)) => '((0 0 1) (0 0 2)))
+
+  (defexamples -unzip-lists
+    (-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) => '((1 2) (3 4) (5 6))
+    (-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) => '((1 4 6 8) (2 5 7 9))
+    (-unzip-lists '((1 2 3) (4 5 6))) => '((1 4) (2 5) (3 6))
+    (-unzip-lists ()) => ()
+    (-unzip-lists '(())) => ()
+    (-unzip-lists '((1))) => '((1))
+    (-unzip-lists '((1 2))) => '((1) (2))
+    (-unzip-lists '((1 2 3))) => '((1) (2) (3))
+    (-unzip-lists '(() ())) => ()
+    (-unzip-lists '((1) ())) => ()
+    (-unzip-lists '(() (1))) => ()
+    (-unzip-lists '((1) (2))) => '((1 2))
+    (-unzip-lists '((1 2) (3))) => '((1 3))
+    (-unzip-lists '((1) (2 3))) => '((1 2))
+    (-unzip-lists '((1 2) (3 4))) => '((1 3) (2 4))
+    (-unzip-lists '(() () ())) => ()
+    (-unzip-lists '((1) () ())) => ()
+    (-unzip-lists '(() (1) ())) => ()
+    (-unzip-lists '(() () (1))) => ()
+    (-unzip-lists '((1) (2) ())) => ()
+    (-unzip-lists '((1) () (2))) => ()
+    (-unzip-lists '(() (1) (2))) => ()
+    (-unzip-lists '((1) (2) (3))) => '((1 2 3))
+    (-unzip-lists '((1 2) (3) (4))) => '((1 3 4))
+    (-unzip-lists '((1) (2 3) (4))) => '((1 2 4))
+    (-unzip-lists '((1) (2) (3 4))) => '((1 2 3))
+    (-unzip-lists '((1 2) (3 4) (5 6))) => '((1 3 5) (2 4 6))
+    (-unzip-lists '((1 2 3) (4 5 6) (7 8 9))) => '((1 4 7) (2 5 8) (3 6 9)))
 
   (defexamples -unzip
-    (-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)))
+    (-unzip (-zip '(1 2) '(3 4) '(5 6))) => '((1 . 2) (3 . 4) (5 . 6))
+    (-unzip '((1 2 3) (4 5 6))) => '((1 . 4) (2 . 5) (3 . 6))
+    (-unzip '((1 2 3) (4 5) (6 7) (8 9))) => '((1 4 6 8) (2 5 7 9))
+    (-unzip ()) => ()
+    (-unzip '(())) => ()
+    (-unzip '((1))) => '((1))
+    (-unzip '((1 2))) => '((1) (2))
+    (-unzip '((1 2 3))) => '((1) (2) (3))
+    (-unzip '(() ())) => ()
+    (-unzip '((1) ())) => ()
+    (-unzip '(() (1))) => ()
+    (-unzip '((1) (2))) => '((1 . 2))
+    (-unzip '((1 2) (3))) => '((1 . 3))
+    (-unzip '((1) (2 3))) => '((1 . 2))
+    (-unzip '((1 2) (3 4))) => '((1 . 3) (2 . 4))
+    (-unzip '(() () ())) => ()
+    (-unzip '((1) () ())) => ()
+    (-unzip '(() (1) ())) => ()
+    (-unzip '(() () (1))) => ()
+    (-unzip '((1) (2) ())) => ()
+    (-unzip '((1) () (2))) => ()
+    (-unzip '(() (1) (2))) => ()
+    (-unzip '((1) (2) (3))) => '((1 2 3))
+    (-unzip '((1 2) (3) (4))) => '((1 3 4))
+    (-unzip '((1) (2 3) (4))) => '((1 2 4))
+    (-unzip '((1) (2) (3 4))) => '((1 2 3))
+    (-unzip '((1 2) (3 4) (5 6))) => '((1 3 5) (2 4 6))
+    (-unzip '((1 2 3) (4 5 6) (7 8 9))) => '((1 4 7) (2 5 8) (3 6 9)))
 
   (defexamples -pad
     (-pad 0 '()) => '(())
@@ -2344,26 +2657,28 @@ or readability."
     (funcall (-fixfn #'sin #'approx=) 0.1) => '(halted . t))
 
   (defexamples -prodfn
-    (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
-    (let ((f '1+)
-          (g '1-)
-          (ff 'string-to-number)
-          (gg 'length)
+    (funcall (-prodfn #'1+ #'1- #'number-to-string) '(1 2 3)) => '(2 1 "3")
+    (-map (-prodfn #'1- #'1+) '((1 2) (3 4) (5 6))) => '((0 3) (2 5) (4 7))
+    (apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) => 6
+    (let ((f #'1+)
+          (g #'1-)
+          (ff #'string-to-number)
+          (gg #'length)
           (input '(1 2))
           (input2 "foo")
           (input3 '("10" '(1 2 3))))
       (and (equal (funcall (-prodfn f g) input)
-                  (funcall (-juxt (-compose f (-partial 'nth 0)) (-compose g 
(-partial 'nth 1))) input))
+                  (funcall (-juxt (-compose f #'car) (-compose g #'cadr))
+                           input))
            (equal (funcall (-compose (-prodfn f g) (-juxt ff gg)) input2)
                   (funcall (-juxt (-compose f ff) (-compose g gg)) input2))
-           (equal (funcall (-compose (-partial 'nth 0) (-prodfn f g)) input)
-                  (funcall (-compose f (-partial 'nth 0)) input))
-           (equal (funcall (-compose (-partial 'nth 1) (-prodfn f g)) input)
-                  (funcall (-compose g (-partial 'nth 1)) input))
+           (equal (funcall (-compose (-partial #'nth 0) (-prodfn f g)) input)
+                  (funcall (-compose f (-partial #'nth 0)) input))
+           (equal (funcall (-compose (-partial #'nth 1) (-prodfn f g)) input)
+                  (funcall (-compose g (-partial #'nth 1)) input))
            (equal (funcall (-compose (-prodfn f g) (-prodfn ff gg)) input3)
-                  (funcall (-prodfn (-compose f ff) (-compose g gg)) 
input3)))) => t))
+                  (funcall (-prodfn (-compose f ff) (-compose g gg)) input3))))
+    => t))
 
 (ert-deftest dash--member-fn ()
   "Test `dash--member-fn'."
@@ -2488,4 +2803,12 @@ or readability."
                    (3 5 4)
                    (3 4 5)))))
 
+(ert-deftest dash--length= ()
+  "Test `dash--length='."
+  (dotimes (n 10)
+    (let ((l (make-list n nil)))
+      (should (dash--length= l n))
+      (should-not (dash--length= l (1- n)))
+      (should-not (dash--length= l (1+ n))))))
+
 ;;; examples.el ends here
diff --git a/readme-template.md b/readme-template.md
index 3065d2c80a..ef33241438 100644
--- a/readme-template.md
+++ b/readme-template.md
@@ -14,7 +14,6 @@ See the end of the file for license conditions.
 ## Contents
 
 * [Change log](#change-log)
-  * [Upcoming breaking change!](#upcoming-breaking-change)
 * [Installation](#installation)
 * [Functions](#functions)
 * [Contribute](#contribute)
@@ -25,18 +24,6 @@ See the end of the file for license conditions.
 
 See the [`NEWS.md`](NEWS.md) file.
 
-### Upcoming breaking change!
-
-- For backward compatibility reasons, `-zip` when called with two
-  lists returns a list of cons cells, rather than a list of proper
-  lists.  This is a clunky API, and may be changed in a future release
-  to always return a list of proper lists, as `-zip-lists` currently
-  does.
-
-  **N.B.:** Do not rely on the current behavior of `-zip` for two
-  lists.  Instead, use `-zip-pair` for a list of cons cells, and
-  `-zip-lists` for a list of proper lists.
-
 ## Installation
 
 Dash is available on [GNU ELPA](https://elpa.gnu.org/), [GNU-devel



reply via email to

[Prev in Thread] Current Thread [Next in Thread]