dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

seq-25.el (26302B)


      1 ;;; seq-25.el --- seq.el implementation for Emacs 25.x -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2014-2023 Free Software Foundation, Inc.
      4 
      5 ;; Author: Nicolas Petton <nicolas@petton.fr>
      6 ;; Keywords: sequences
      7 
      8 ;; Maintainer: emacs-devel@gnu.org
      9 
     10 ;; This file is part of GNU Emacs.
     11 
     12 ;; GNU Emacs is free software: you can redistribute it and/or modify
     13 ;; it under the terms of the GNU General Public License as published by
     14 ;; the Free Software Foundation, either version 3 of the License, or
     15 ;; (at your option) any later version.
     16 
     17 ;; GNU Emacs is distributed in the hope that it will be useful,
     18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20 ;; GNU General Public License for more details.
     21 
     22 ;; You should have received a copy of the GNU General Public License
     23 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
     24 
     25 ;;; Commentary:
     26 
     27 ;; Sequence-manipulation functions that complement basic functions
     28 ;; provided by subr.el.
     29 ;;
     30 ;; All functions are prefixed with "seq-".
     31 ;;
     32 ;; All provided functions work on lists, strings and vectors.
     33 ;;
     34 ;; Functions taking a predicate or iterating over a sequence using a
     35 ;; function as argument take the function as their first argument and
     36 ;; the sequence as their second argument.  All other functions take
     37 ;; the sequence as their first argument.
     38 ;;
     39 ;; seq.el can be extended to support new type of sequences.  Here are
     40 ;; the generic functions that must be implemented by new seq types:
     41 ;; - `seq-elt'
     42 ;; - `seq-length'
     43 ;; - `seq-do'
     44 ;; - `seqp'
     45 ;; - `seq-subseq'
     46 ;; - `seq-into-sequence'
     47 ;; - `seq-copy'
     48 ;; - `seq-into'
     49 
     50 ;;; Code:
     51 
     52 ;; When loading seq.el in Emacs 24.x, this file gets byte-compiled, even if
     53 ;; never used.  This takes care of byte-compilation warnings is emitted, by
     54 ;; emitting nil in the macro expansion in Emacs 24.x.
     55 (defmacro seq--when-emacs-25-p (&rest body)
     56   "Execute BODY if in Emacs>=25.x."
     57   (declare (indent (lambda (&rest x) 0)) (debug t))
     58   (when (version<= "25" emacs-version)
     59     `(progn ,@body)))
     60 
     61 (defalias 'seq--take
     62   (if (>= emacs-major-version 29)
     63       'take
     64     (lambda (n list)                ; copied here from the `compat' package
     65       "Return the first N elements of LIST.
     66 If N is zero or negative, return nil.
     67 If N is greater or equal to the length of LIST, return LIST (or a copy)."
     68       (let (copy)
     69         (while (and (< 0 n) list)
     70           (push (pop list) copy)
     71           (setq n (1- n)))
     72         (nreverse copy)))))
     73 
     74 (seq--when-emacs-25-p
     75 
     76 (eval-when-compile (require 'cl-generic))
     77 
     78 ;; We used to use some sequence functions from cl-lib, but this
     79 ;; dependency was swapped around so that it's easier to make seq.el
     80 ;; preloaded.  See also Bug#39761#26.
     81 
     82 (defmacro seq-doseq (spec &rest body)
     83   "Loop over a SEQUENCE, evaluating BODY with VAR bound to each of its elements.
     84 
     85 Similar to `dolist' but can be applied to lists, strings, and vectors.
     86 
     87 \(fn (VAR SEQUENCE) BODY...)"
     88   (declare (indent 1) (debug ((symbolp form &optional form) body)))
     89   `(seq-do (lambda (,(car spec))
     90              ,@body)
     91            ,(cadr spec)))
     92 
     93 (pcase-defmacro seq (&rest patterns)
     94   "Build a `pcase' pattern that matches elements of SEQUENCE.
     95 
     96 The `pcase' pattern will match each element of PATTERNS against the
     97 corresponding element of SEQUENCE.
     98 
     99 Extra elements of the sequence are ignored if fewer PATTERNS are
    100 given, and the match does not fail."
    101   `(and (pred seqp)
    102         ,@(seq--make-pcase-bindings patterns)))
    103 
    104 (defmacro seq-let (args sequence &rest body)
    105   "Bind the variables in ARGS to the elements of SEQUENCE, then evaluate BODY.
    106 
    107 ARGS can also include the `&rest' marker followed by a variable
    108 name to be bound to the rest of SEQUENCE."
    109   (declare (indent 2) (debug (sexp form body)))
    110   `(pcase-let ((,(seq--make-pcase-patterns args) ,sequence))
    111      ,@body))
    112 
    113 (defmacro seq-setq (args sequence)
    114   "Assign the elements of SEQUENCE to the variables in ARGS.
    115 
    116 ARGS can also include the `&rest' marker followed by a variable
    117 name to be bound to the rest of SEQUENCE."
    118   (declare (debug (sexp form)))
    119   `(pcase-setq ,(seq--make-pcase-patterns args) ,sequence))
    120 
    121 
    122 ;;; Basic seq functions that have to be implemented by new sequence types
    123 (cl-defgeneric seq-elt (sequence n)
    124   "Return the Nth element of SEQUENCE."
    125   (elt sequence n))
    126 
    127 ;; Default gv setters for `seq-elt'.
    128 ;; It can be a good idea for new sequence implementations to provide a
    129 ;; "gv-setter" for `seq-elt'.
    130 (cl-defmethod (setf seq-elt) (store (sequence array) n)
    131   (aset sequence n store))
    132 
    133 (cl-defmethod (setf seq-elt) (store (sequence cons) n)
    134   (setcar (nthcdr n sequence) store))
    135 
    136 (cl-defgeneric seq-length (sequence)
    137   "Return the number of elements in SEQUENCE."
    138   (length sequence))
    139 
    140 (defun seq-first (sequence)
    141   "Return the first element of SEQUENCE."
    142   (seq-elt sequence 0))
    143 
    144 (defun seq-rest (sequence)
    145   "Return SEQUENCE with its first element removed."
    146   (seq-drop sequence 1))
    147 
    148 (cl-defgeneric seq-do (function sequence)
    149   "Apply FUNCTION to each element of SEQUENCE.
    150 Presumably, FUNCTION has useful side effects.
    151 Return SEQUENCE."
    152   (mapc function sequence))
    153 
    154 (defalias 'seq-each #'seq-do)
    155 
    156 (defun seq-do-indexed (function sequence)
    157   "Apply FUNCTION to each element of SEQUENCE and return nil.
    158 Unlike `seq-map', FUNCTION takes two arguments: the element of
    159 the sequence, and its index within the sequence."
    160   (let ((index 0))
    161     (seq-do (lambda (elt)
    162               (funcall function elt index)
    163               (setq index (1+ index)))
    164             sequence))
    165   nil)
    166 
    167 (cl-defgeneric seqp (object)
    168   "Return non-nil if OBJECT is a sequence, nil otherwise."
    169   (sequencep object))
    170 
    171 (cl-defgeneric seq-copy (sequence)
    172   "Return a shallow copy of SEQUENCE."
    173   (copy-sequence sequence))
    174 
    175 ;;;###autoload
    176 (cl-defgeneric seq-subseq (sequence start &optional end)
    177   "Return the sequence of elements of SEQUENCE from START to END.
    178 END is exclusive.
    179 
    180 If END is omitted, it defaults to the length of the sequence.  If
    181 START or END is negative, it counts from the end.  Signal an
    182 error if START or END are outside of the sequence (i.e too large
    183 if positive or too small if negative)."
    184   (cond
    185    ((or (stringp sequence) (vectorp sequence)) (substring sequence start end))
    186    ((listp sequence)
    187     (let (len
    188           (orig-start start)
    189           (orig-end end))
    190       (and end (< end 0) (setq end (+ end (setq len (length sequence)))))
    191       (if (< start 0) (setq start (+ start (or len (setq len (length sequence))))))
    192       (unless (>= start 0)
    193         (error "Start index out of bounds: %s" orig-start))
    194       (when (> start 0)
    195         (setq sequence (nthcdr (1- start) sequence))
    196         (unless sequence
    197           (error "Start index out of bounds: %s" orig-start))
    198         (setq sequence (cdr sequence)))
    199       (if end
    200           (let ((n (- end start)))
    201             (when (or (< n 0)
    202                       (if len
    203                           (> end len)
    204                         (and (> n 0) (null (nthcdr (1- n) sequence)))))
    205               (error "End index out of bounds: %s" orig-end))
    206             (seq--take n sequence))
    207         (copy-sequence sequence))))
    208    (t (error "Unsupported sequence: %s" sequence))))
    209 
    210 
    211 (cl-defgeneric seq-map (function sequence)
    212   "Return the result of applying FUNCTION to each element of SEQUENCE."
    213   (let (result)
    214     (seq-do (lambda (elt)
    215               (push (funcall function elt) result))
    216             sequence)
    217     (nreverse result)))
    218 
    219 (defun seq-map-indexed (function sequence)
    220   "Return the result of applying FUNCTION to each element of SEQUENCE.
    221 Unlike `seq-map', FUNCTION takes two arguments: the element of
    222 the sequence, and its index within the sequence."
    223   (let ((index 0))
    224     (seq-map (lambda (elt)
    225                (prog1
    226                    (funcall function elt index)
    227                  (setq index (1+ index))))
    228              sequence)))
    229 
    230 
    231 ;; faster implementation for sequences (sequencep)
    232 (cl-defmethod seq-map (function (sequence sequence))
    233   (mapcar function sequence))
    234 
    235 (cl-defgeneric seq-mapn (function sequence &rest sequences)
    236   "Return the result of applying FUNCTION to each element of SEQUENCEs.
    237 Like `seq-map', but FUNCTION is mapped over all SEQUENCEs.
    238 The arity of FUNCTION must match the number of SEQUENCEs, and the
    239 mapping stops on the shortest sequence.
    240 Return a list of the results.
    241 
    242 \(fn FUNCTION SEQUENCES...)"
    243   (let ((result nil)
    244         (sequences (seq-map (lambda (s)
    245                               (seq-into s 'list))
    246                             (cons sequence sequences))))
    247     (while (not (memq nil sequences))
    248       (push (apply function (seq-map #'car sequences)) result)
    249       (setq sequences (seq-map #'cdr sequences)))
    250     (nreverse result)))
    251 
    252 (cl-defgeneric seq-drop (sequence n)
    253   "Remove the first N elements of SEQUENCE and return the resulting sequence.
    254 The result is a sequence of the same type as SEQUENCE.
    255 
    256 If N is a negative integer or zero, SEQUENCE is returned."
    257   (if (<= n 0)
    258       sequence
    259     (let ((length (seq-length sequence)))
    260       (seq-subseq sequence (min n length) length))))
    261 
    262 ;;;###autoload
    263 (cl-defgeneric seq-take (sequence n)
    264   "Return the sequence made of the first N elements of SEQUENCE.
    265 The result is a sequence of the same type as SEQUENCE.
    266 
    267 If N is a negative integer or zero, an empty sequence is
    268 returned."
    269   (seq-subseq sequence 0 (min (max n 0) (seq-length sequence))))
    270 
    271 (cl-defgeneric seq-drop-while (pred sequence)
    272   "Remove the successive elements of SEQUENCE for which PRED returns non-nil.
    273 PRED is a function of one argument.  The function keeps removing
    274 elements from SEQUENCE until PRED returns nil for an element.
    275 Value is a sequence of the same type as SEQUENCE."
    276   (seq-drop sequence (seq--count-successive pred sequence)))
    277 
    278 (cl-defgeneric seq-take-while (pred sequence)
    279   "Take the successive elements of SEQUENCE for which PRED returns non-nil.
    280 PRED is a function of one argument.  The function keeps collecting
    281 elements from SEQUENCE and adding them to the result until PRED
    282 returns nil for an element.
    283 Value is a sequence of the same type as SEQUENCE."
    284   (seq-take sequence (seq--count-successive pred sequence)))
    285 
    286 (cl-defgeneric seq-empty-p (sequence)
    287   "Return non-nil if the SEQUENCE is empty, nil otherwise."
    288   (= 0 (seq-length sequence)))
    289 
    290 (cl-defgeneric seq-sort (pred sequence)
    291   "Sort SEQUENCE using PRED as the sorting comparison function.
    292 The result is a sequence of the same type as SEQUENCE."
    293   (let ((result (seq-sort pred (append sequence nil))))
    294     (seq-into result (type-of sequence))))
    295 
    296 (cl-defmethod seq-sort (pred (list list))
    297   (sort (seq-copy list) pred))
    298 
    299 ;;;###autoload
    300 (defun seq-sort-by (function pred sequence)
    301   "Sort SEQUENCE transformed by FUNCTION using PRED as the comparison function.
    302 Elements of SEQUENCE are transformed by FUNCTION before being
    303 sorted.  FUNCTION must be a function of one argument."
    304   (seq-sort (lambda (a b)
    305               (funcall pred
    306                        (funcall function a)
    307                        (funcall function b)))
    308             sequence))
    309 
    310 (cl-defgeneric seq-reverse (sequence)
    311   "Return a sequence with elements of SEQUENCE in reverse order."
    312   (let ((result '()))
    313     (seq-map (lambda (elt)
    314                (push elt result))
    315              sequence)
    316     (seq-into result (type-of sequence))))
    317 
    318 ;; faster implementation for sequences (sequencep)
    319 (cl-defmethod seq-reverse ((sequence sequence))
    320   (reverse sequence))
    321 
    322 (cl-defgeneric seq-concatenate (type &rest sequences)
    323   "Concatenate SEQUENCES into a single sequence of type TYPE.
    324 TYPE must be one of following symbols: `vector', `string' or `list'.
    325 
    326 \n(fn TYPE SEQUENCE...)"
    327   (setq sequences (mapcar #'seq-into-sequence sequences))
    328   (pcase type
    329     ('vector (apply #'vconcat sequences))
    330     ('string (apply #'concat sequences))
    331     ('list (apply #'append (append sequences '(nil))))
    332     (_ (error "Not a sequence type name: %S" type))))
    333 
    334 (cl-defgeneric seq-into-sequence (sequence)
    335   "Convert SEQUENCE into a sequence.
    336 
    337 The default implementation is to signal an error if SEQUENCE is not a
    338 sequence, specific functions should be implemented for new types
    339 of sequence."
    340   (unless (sequencep sequence)
    341     (error "Cannot convert %S into a sequence" sequence))
    342   sequence)
    343 
    344 (cl-defgeneric seq-into (sequence type)
    345   "Concatenate the elements of SEQUENCE into a sequence of type TYPE.
    346 TYPE can be one of the following symbols: `vector', `string' or
    347 `list'."
    348   (pcase type
    349     (`vector (seq--into-vector sequence))
    350     (`string (seq--into-string sequence))
    351     (`list (seq--into-list sequence))
    352     (_ (error "Not a sequence type name: %S" type))))
    353 
    354 ;;;###autoload
    355 (cl-defgeneric seq-filter (pred sequence)
    356   "Return a list of all the elements in SEQUENCE for which PRED returns non-nil."
    357   (let ((exclude (make-symbol "exclude")))
    358     (delq exclude (seq-map (lambda (elt)
    359                              (if (funcall pred elt)
    360                                  elt
    361                                exclude))
    362                            sequence))))
    363 
    364 ;;;###autoload
    365 (cl-defgeneric seq-remove (pred sequence)
    366   "Return a list of all the elements in SEQUENCE for which PRED returns nil."
    367   (seq-filter (lambda (elt) (not (funcall pred elt)))
    368               sequence))
    369 
    370 ;;;###autoload
    371 (cl-defgeneric seq-remove-at-position (sequence n)
    372   "Return a copy of SEQUENCE with the element at index N removed.
    373 
    374 N is the (zero-based) index of the element that should not be in
    375 the result.
    376 
    377 The result is a sequence of the same type as SEQUENCE."
    378   (seq-concatenate
    379    (let ((type (type-of sequence)))
    380      (if (eq type 'cons) 'list type))
    381    (seq-subseq sequence 0 n)
    382    (seq-subseq sequence (1+ n))))
    383 
    384 ;;;###autoload
    385 (cl-defgeneric seq-reduce (function sequence initial-value)
    386   "Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
    387 
    388 Return the result of calling FUNCTION with INITIAL-VALUE and the
    389 first element of SEQUENCE, then calling FUNCTION with that result
    390 and the second element of SEQUENCE, then with that result and the
    391 third element of SEQUENCE, etc.  FUNCTION will be called with
    392 INITIAL-VALUE (and then the accumulated value) as the first
    393 argument, and the elements from SEQUENCE as the second argument.
    394 
    395 If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called."
    396   (if (seq-empty-p sequence)
    397       initial-value
    398     (let ((acc initial-value))
    399       (seq-doseq (elt sequence)
    400         (setq acc (funcall function acc elt)))
    401       acc)))
    402 
    403 ;;;###autoload
    404 (cl-defgeneric seq-every-p (pred sequence)
    405   "Return non-nil if PRED returns non-nil for all the elements of SEQUENCE."
    406   (catch 'seq--break
    407     (seq-doseq (elt sequence)
    408       (or (funcall pred elt)
    409           (throw 'seq--break nil)))
    410     t))
    411 
    412 ;;;###autoload
    413 (cl-defgeneric seq-some (pred sequence)
    414   "Return non-nil if PRED returns non-nil for at least one element of SEQUENCE.
    415 If the value is non-nil, it is the first non-nil value returned by PRED."
    416   (catch 'seq--break
    417     (seq-doseq (elt sequence)
    418       (let ((result (funcall pred elt)))
    419         (when result
    420           (throw 'seq--break result))))
    421     nil))
    422 
    423 ;;;###autoload
    424 (cl-defgeneric seq-find (pred sequence &optional default)
    425   "Return the first element in SEQUENCE for which PRED returns non-nil.
    426 If no such element is found, return DEFAULT.
    427 
    428 Note that `seq-find' has an ambiguity if the found element is
    429 identical to DEFAULT, as in that case it is impossible to know
    430 whether an element was found or not."
    431   (catch 'seq--break
    432     (seq-doseq (elt sequence)
    433       (when (funcall pred elt)
    434         (throw 'seq--break elt)))
    435     default))
    436 
    437 (cl-defgeneric seq-count (pred sequence)
    438   "Return the number of elements in SEQUENCE for which PRED returns non-nil."
    439   (let ((count 0))
    440     (seq-doseq (elt sequence)
    441       (when (funcall pred elt)
    442         (setq count (+ 1 count))))
    443     count))
    444 
    445 (cl-defgeneric seq-contains (sequence elt &optional testfn)
    446   "Return the first element in SEQUENCE that is \"equal\" to ELT.
    447 \"Equality\" is defined by the function TESTFN, which defaults to `equal'."
    448   (declare (obsolete seq-contains-p "27.1"))
    449   (seq-some (lambda (e)
    450               (when (funcall (or testfn #'equal) elt e)
    451                 e))
    452             sequence))
    453 
    454 (cl-defgeneric seq-contains-p (sequence elt &optional testfn)
    455   "Return non-nil if SEQUENCE contains an element \"equal\" to ELT.
    456 \"Equality\" is defined by the function TESTFN, which defaults to `equal'."
    457   (catch 'seq--break
    458     (seq-doseq (e sequence)
    459       (let ((r (funcall (or testfn #'equal) e elt)))
    460         (when r
    461           (throw 'seq--break r))))
    462     nil))
    463 
    464 (cl-defgeneric seq-set-equal-p (sequence1 sequence2 &optional testfn)
    465   "Return non-nil if SEQUENCE1 and SEQUENCE2 contain the same elements.
    466 The order of the elements in the sequences is not important.
    467 \"Equality\" of elements is defined by the function TESTFN, which
    468 defaults to `equal'."
    469   (and (seq-every-p (lambda (item1) (seq-contains-p sequence2 item1 testfn)) sequence1)
    470        (seq-every-p (lambda (item2) (seq-contains-p sequence1 item2 testfn)) sequence2)))
    471 
    472 ;;;###autoload
    473 (cl-defgeneric seq-position (sequence elt &optional testfn)
    474   "Return the (zero-based) index of the first element in SEQUENCE \"equal\" to ELT.
    475 \"Equality\" is defined by the function TESTFN, which defaults to `equal'."
    476   (let ((index 0))
    477     (catch 'seq--break
    478       (seq-doseq (e sequence)
    479         (when (funcall (or testfn #'equal) e elt)
    480           (throw 'seq--break index))
    481         (setq index (1+ index)))
    482       nil)))
    483 
    484 ;;;###autoload
    485 (cl-defgeneric seq-positions (sequence elt &optional testfn)
    486   "Return list of indices of SEQUENCE elements for which TESTFN returns non-nil.
    487 
    488 TESTFN is a two-argument function which is called with each element of
    489 SEQUENCE as the first argument and ELT as the second.
    490 TESTFN defaults to `equal'.
    491 
    492 The result is a list of (zero-based) indices."
    493   (let ((result '()))
    494     (seq-do-indexed
    495      (lambda (e index)
    496        (when (funcall (or testfn #'equal) e elt)
    497          (push index result)))
    498      sequence)
    499     (nreverse result)))
    500 
    501 ;;;###autoload
    502 (cl-defgeneric seq-uniq (sequence &optional testfn)
    503   "Return a list of the elements of SEQUENCE with duplicates removed.
    504 TESTFN is used to compare elements, and defaults to `equal'."
    505   (let ((result '()))
    506     (seq-doseq (elt sequence)
    507       (unless (seq-contains-p result elt testfn)
    508         (setq result (cons elt result))))
    509     (nreverse result)))
    510 
    511 (cl-defmethod seq-uniq ((sequence list) &optional testfn)
    512   (let ((result nil))
    513     (if (not testfn)
    514         ;; Fast path.  If the list is long, use a hash table to speed
    515         ;; things up even more.
    516         (let ((l (length sequence)))
    517           (if (> l 100)
    518               (let ((hash (make-hash-table :test #'equal :size l)))
    519                 (while sequence
    520                   (unless (gethash (car sequence) hash)
    521                     (setf (gethash (car sequence) hash) t)
    522                     (push (car sequence) result))
    523                   (setq sequence (cdr sequence))))
    524             ;; Short list.
    525             (while sequence
    526               (unless (member (car sequence) result)
    527                 (push (car sequence) result))
    528               (pop sequence))))
    529       ;; Slower path.
    530       (while sequence
    531         (unless (seq-find (lambda (elem)
    532                             (funcall testfn elem (car sequence)))
    533                           result)
    534           (push (car sequence) result))
    535         (pop sequence)))
    536     (nreverse result)))
    537 
    538 (cl-defgeneric seq-mapcat (function sequence &optional type)
    539   "Concatenate the results of applying FUNCTION to each element of SEQUENCE.
    540 The result is a sequence of type TYPE; TYPE defaults to `list'."
    541   (apply #'seq-concatenate (or type 'list)
    542          (seq-map function sequence)))
    543 
    544 (cl-defgeneric seq-partition (sequence n)
    545   "Return list of elements of SEQUENCE grouped into sub-sequences of length N.
    546 The last sequence may contain less than N elements.  If N is a
    547 negative integer or 0, the function returns nil."
    548   (unless (< n 1)
    549     (let ((result '()))
    550       (while (not (seq-empty-p sequence))
    551         (push (seq-take sequence n) result)
    552         (setq sequence (seq-drop sequence n)))
    553       (nreverse result))))
    554 
    555 ;;;###autoload
    556 (cl-defgeneric seq-union (sequence1 sequence2 &optional testfn)
    557   "Return a list of all the elements that appear in either SEQUENCE1 or SEQUENCE2.
    558 \"Equality\" of elements is defined by the function TESTFN, which
    559 defaults to `equal'."
    560   (let* ((accum (lambda (acc elt)
    561                   (if (seq-contains-p acc elt testfn)
    562                       acc
    563                     (cons elt acc))))
    564          (result (seq-reduce accum sequence2
    565                              (seq-reduce accum sequence1 '()))))
    566     (nreverse result)))
    567 
    568 ;;;###autoload
    569 (cl-defgeneric seq-intersection (sequence1 sequence2 &optional testfn)
    570   "Return a list of all the elements that appear in both SEQUENCE1 and SEQUENCE2.
    571 \"Equality\" of elements is defined by the function TESTFN, which
    572 defaults to `equal'."
    573   (seq-reduce (lambda (acc elt)
    574                 (if (seq-contains-p sequence2 elt testfn)
    575                     (cons elt acc)
    576                   acc))
    577               (seq-reverse sequence1)
    578               '()))
    579 
    580 (cl-defgeneric seq-difference (sequence1 sequence2 &optional testfn)
    581   "Return list of all the elements that appear in SEQUENCE1 but not in SEQUENCE2.
    582 \"Equality\" of elements is defined by the function TESTFN, which
    583 defaults to `equal'."
    584   (seq-reduce (lambda (acc elt)
    585                 (if (seq-contains-p sequence2 elt testfn)
    586                     acc
    587                   (cons elt acc)))
    588               (seq-reverse sequence1)
    589               '()))
    590 
    591 ;;;###autoload
    592 (cl-defgeneric seq-group-by (function sequence)
    593   "Apply FUNCTION to each element of SEQUENCE.
    594 Separate the elements of SEQUENCE into an alist using the results as
    595 keys.  Keys are compared using `equal'."
    596   (seq-reduce
    597    (lambda (acc elt)
    598      (let* ((key (funcall function elt))
    599             (cell (assoc key acc)))
    600        (if cell
    601            (setcdr cell (push elt (cdr cell)))
    602          (push (list key elt) acc))
    603        acc))
    604    (seq-reverse sequence)
    605    nil))
    606 
    607 (cl-defgeneric seq-min (sequence)
    608   "Return the smallest element of SEQUENCE.
    609 SEQUENCE must be a sequence of numbers or markers."
    610   (apply #'min (seq-into sequence 'list)))
    611 
    612 ;;;###autoload
    613 (cl-defgeneric seq-max (sequence)
    614   "Return the largest element of SEQUENCE.
    615 SEQUENCE must be a sequence of numbers or markers."
    616   (apply #'max (seq-into sequence 'list)))
    617 
    618 (defun seq--count-successive (pred sequence)
    619   "Count successive elements in SEQUENCE for which PRED returns non-nil."
    620   (let ((n 0)
    621         (len (seq-length sequence)))
    622     (while (and (< n len)
    623                 (funcall pred (seq-elt sequence n)))
    624       (setq n (+ 1 n)))
    625     n))
    626 
    627 (defun seq--make-pcase-bindings (args)
    628   "Return list of bindings of the variables in ARGS to the elements of a sequence."
    629   (let ((bindings '())
    630         (index 0)
    631         (rest-marker nil))
    632     (seq-doseq (name args)
    633       (unless rest-marker
    634         (pcase name
    635           (`&rest
    636            (progn (push `(app (pcase--flip seq-drop ,index)
    637                               ,(seq--elt-safe args (1+ index)))
    638                         bindings)
    639                   (setq rest-marker t)))
    640           (_
    641            (push `(app (pcase--flip seq--elt-safe ,index) ,name) bindings))))
    642       (setq index (1+ index)))
    643     bindings))
    644 
    645 (defun seq--make-pcase-patterns (args)
    646   "Return a list of `(seq ...)' pcase patterns from the argument list ARGS."
    647   (cons 'seq
    648         (seq-map (lambda (elt)
    649                    (if (seqp elt)
    650                        (seq--make-pcase-patterns elt)
    651                      elt))
    652                  args)))
    653 
    654 ;; TODO: make public?
    655 (defun seq--elt-safe (sequence n)
    656   "Return the element of SEQUENCE whose zero-based index is N.
    657 If no element is found, return nil."
    658   (ignore-errors (seq-elt sequence n)))
    659 
    660 ;;;###autoload
    661 (cl-defgeneric seq-random-elt (sequence)
    662   "Return a randomly chosen element from SEQUENCE.
    663 Signal an error if SEQUENCE is empty."
    664   (if (seq-empty-p sequence)
    665       (error "Sequence cannot be empty")
    666     (seq-elt sequence (random (seq-length sequence)))))
    667 
    668 
    669 ;;; Optimized implementations for lists
    670 
    671 (cl-defmethod seq-drop ((list list) n)
    672   "Optimized implementation of `seq-drop' for lists."
    673   (nthcdr n list))
    674 
    675 (cl-defmethod seq-take ((list list) n)
    676   "Optimized implementation of `seq-take' for lists."
    677   (seq--take n list))
    678 
    679 (cl-defmethod seq-drop-while (pred (list list))
    680   "Optimized implementation of `seq-drop-while' for lists."
    681   (while (and list (funcall pred (car list)))
    682     (setq list (cdr list)))
    683   list)
    684 
    685 (cl-defmethod seq-empty-p ((list list))
    686   "Optimized implementation of `seq-empty-p' for lists."
    687   (null list))
    688 
    689 
    690 (defun seq--into-list (sequence)
    691   "Concatenate the elements of SEQUENCE into a list."
    692   (if (listp sequence)
    693       sequence
    694     (append sequence nil)))
    695 
    696 (defun seq--into-vector (sequence)
    697   "Concatenate the elements of SEQUENCE into a vector."
    698   (if (vectorp sequence)
    699       sequence
    700     (vconcat sequence)))
    701 
    702 (defun seq--into-string (sequence)
    703   "Concatenate the elements of SEQUENCE into a string."
    704   (if (stringp sequence)
    705       sequence
    706     (concat sequence)))
    707 
    708 (defun seq--activate-font-lock-keywords ()
    709   "Activate font-lock keywords for some symbols defined in seq."
    710   (font-lock-add-keywords 'emacs-lisp-mode
    711                           '("\\<seq-doseq\\>" "\\<seq-let\\>")))
    712 
    713 (defun seq-split (sequence length)
    714   "Split SEQUENCE into a list of sub-sequences of at most LENGTH elements.
    715 All the sub-sequences will be LENGTH long, except the last one,
    716 which may be shorter."
    717   (when (< length 1)
    718     (error "Sub-sequence length must be larger than zero"))
    719   (let ((result nil)
    720         (seq-length (length sequence))
    721         (start 0))
    722     (while (< start seq-length)
    723       (push (seq-subseq sequence start
    724                         (setq start (min seq-length (+ start length))))
    725             result))
    726     (nreverse result)))
    727 
    728 (defun seq-keep (function sequence)
    729   "Apply FUNCTION to SEQUENCE and return the list of all the non-nil results."
    730   (delq nil (seq-map function sequence)))
    731 
    732 (unless (fboundp 'elisp--font-lock-flush-elisp-buffers)
    733   ;; In Emacsā‰„25, (via elisp--font-lock-flush-elisp-buffers and a few others)
    734   ;; we automatically highlight macros.
    735   (add-hook 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords))
    736 
    737 ) ; end seq--when-emacs-25-p
    738 (provide 'seq-25)
    739 ;;; seq-25.el ends here