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