final tt updates
[emacs-init.git] / elpa / dash-20190424.1804 / dash.el
1 ;;; dash.el --- A modern list library for Emacs  -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
4
5 ;; Author: Magnar Sveen <magnars@gmail.com>
6 ;; Version: 2.16.0
7 ;; Package-Version: 20190424.1804
8 ;; Keywords: lists
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;; A modern list api for Emacs.
26 ;;
27 ;; See documentation on https://github.com/magnars/dash.el#functions
28 ;;
29 ;; **Please note** The lexical binding in this file is not utilised at the
30 ;; moment. We will take full advantage of lexical binding in an upcoming 3.0
31 ;; release of Dash. In the meantime, we've added the pragma to avoid a bug that
32 ;; you can read more about in https://github.com/magnars/dash.el/issues/130.
33 ;;
34
35 ;;; Code:
36
37 (defgroup dash ()
38   "Customize group for dash.el"
39   :group 'lisp
40   :prefix "dash-")
41
42 (defun dash--enable-fontlock (symbol value)
43   (when value
44     (dash-enable-font-lock))
45   (set-default symbol value))
46
47 (defcustom dash-enable-fontlock nil
48   "If non-nil, enable fontification of dash functions, macros and
49 special values."
50   :type 'boolean
51   :set 'dash--enable-fontlock
52   :group 'dash)
53
54 (defmacro !cons (car cdr)
55   "Destructive: Set CDR to the cons of CAR and CDR."
56   `(setq ,cdr (cons ,car ,cdr)))
57
58 (defmacro !cdr (list)
59   "Destructive: Set LIST to the cdr of LIST."
60   `(setq ,list (cdr ,list)))
61
62 (defmacro --each (list &rest body)
63   "Anaphoric form of `-each'."
64   (declare (debug (form body))
65            (indent 1))
66   (let ((l (make-symbol "list")))
67     `(let ((,l ,list)
68            (it-index 0))
69        (while ,l
70          (let ((it (car ,l)))
71            ,@body)
72          (setq it-index (1+ it-index))
73          (!cdr ,l)))))
74
75 (defmacro -doto (eval-initial-value &rest forms)
76   "Eval a form, then insert that form as the 2nd argument to other forms.
77 The EVAL-INITIAL-VALUE form is evaluated once. Its result is
78 passed to FORMS, which are then evaluated sequentially. Returns
79 the target form."
80   (declare (indent 1))
81   (let ((retval (make-symbol "value")))
82     `(let ((,retval ,eval-initial-value))
83        ,@(mapcar (lambda (form)
84                    (if (sequencep form)
85                        `(,(-first-item form) ,retval ,@(cdr form))
86                      `(funcall form ,retval)))
87                  forms)
88        ,retval)))
89
90 (defmacro --doto (eval-initial-value &rest forms)
91   "Anaphoric form of `-doto'.
92 Note: `it' is not required in each form."
93   (declare (indent 1))
94   `(let ((it ,eval-initial-value))
95      ,@forms
96      it))
97
98 (defun -each (list fn)
99   "Call FN with every item in LIST. Return nil, used for side-effects only."
100   (--each list (funcall fn it)))
101
102 (put '-each 'lisp-indent-function 1)
103
104 (defalias '--each-indexed '--each)
105
106 (defun -each-indexed (list fn)
107   "Call (FN index item) for each item in LIST.
108
109 In the anaphoric form `--each-indexed', the index is exposed as symbol `it-index'.
110
111 See also: `-map-indexed'."
112   (--each list (funcall fn it-index it)))
113 (put '-each-indexed 'lisp-indent-function 1)
114
115 (defmacro --each-while (list pred &rest body)
116   "Anaphoric form of `-each-while'."
117   (declare (debug (form form body))
118            (indent 2))
119   (let ((l (make-symbol "list"))
120         (c (make-symbol "continue")))
121     `(let ((,l ,list)
122            (,c t)
123            (it-index 0))
124        (while (and ,l ,c)
125          (let ((it (car ,l)))
126            (if (not ,pred) (setq ,c nil) ,@body))
127          (setq it-index (1+ it-index))
128          (!cdr ,l)))))
129
130 (defun -each-while (list pred fn)
131   "Call FN with every item in LIST while (PRED item) is non-nil.
132 Return nil, used for side-effects only."
133   (--each-while list (funcall pred it) (funcall fn it)))
134
135 (put '-each-while 'lisp-indent-function 2)
136
137 (defmacro --each-r (list &rest body)
138   "Anaphoric form of `-each-r'."
139   (declare (debug (form body))
140            (indent 1))
141   (let ((v (make-symbol "vector")))
142     ;; Implementation note: building vector is considerably faster
143     ;; than building a reversed list (vector takes less memory, so
144     ;; there is less GC), plus length comes naturally.  In-place
145     ;; 'nreverse' would be faster still, but BODY would be able to see
146     ;; that, even if modification was reversed before we return.
147     `(let* ((,v (vconcat ,list))
148             (it-index (length ,v))
149             it)
150        (while (> it-index 0)
151          (setq it-index (1- it-index))
152          (setq it (aref ,v it-index))
153          ,@body))))
154
155 (defun -each-r (list fn)
156   "Call FN with every item in LIST in reversed order.
157  Return nil, used for side-effects only."
158   (--each-r list (funcall fn it)))
159
160 (defmacro --each-r-while (list pred &rest body)
161   "Anaphoric form of `-each-r-while'."
162   (declare (debug (form form body))
163            (indent 2))
164   (let ((v (make-symbol "vector")))
165     `(let* ((,v (vconcat ,list))
166             (it-index (length ,v))
167             it)
168        (while (> it-index 0)
169          (setq it-index (1- it-index))
170          (setq it (aref ,v it-index))
171          (if (not ,pred)
172              (setq it-index -1)
173            ,@body)))))
174
175 (defun -each-r-while (list pred fn)
176   "Call FN with every item in reversed LIST while (PRED item) is non-nil.
177 Return nil, used for side-effects only."
178   (--each-r-while list (funcall pred it) (funcall fn it)))
179
180 (defmacro --dotimes (num &rest body)
181   "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1."
182   (declare (debug (form body))
183            (indent 1))
184   (let ((n (make-symbol "num")))
185     `(let ((,n ,num)
186            (it 0))
187        (while (< it ,n)
188          ,@body
189          (setq it (1+ it))))))
190
191 (defun -dotimes (num fn)
192   "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1."
193   (--dotimes num (funcall fn it)))
194
195 (put '-dotimes 'lisp-indent-function 1)
196
197 (defun -map (fn list)
198   "Return a new list consisting of the result of applying FN to the items in LIST."
199   (mapcar fn list))
200
201 (defmacro --map (form list)
202   "Anaphoric form of `-map'."
203   (declare (debug (form form)))
204   `(mapcar (lambda (it) ,form) ,list))
205
206 (defmacro --reduce-from (form initial-value list)
207   "Anaphoric form of `-reduce-from'."
208   (declare (debug (form form form)))
209   `(let ((acc ,initial-value))
210      (--each ,list (setq acc ,form))
211      acc))
212
213 (defun -reduce-from (fn initial-value list)
214   "Return the result of applying FN to INITIAL-VALUE and the
215 first item in LIST, then applying FN to that result and the 2nd
216 item, etc. If LIST contains no items, return INITIAL-VALUE and
217 do not call FN.
218
219 In the anaphoric form `--reduce-from', the accumulated value is
220 exposed as symbol `acc'.
221
222 See also: `-reduce', `-reduce-r'"
223   (--reduce-from (funcall fn acc it) initial-value list))
224
225 (defmacro --reduce (form list)
226   "Anaphoric form of `-reduce'."
227   (declare (debug (form form)))
228   (let ((lv (make-symbol "list-value")))
229     `(let ((,lv ,list))
230        (if ,lv
231            (--reduce-from ,form (car ,lv) (cdr ,lv))
232          (let (acc it) ,form)))))
233
234 (defun -reduce (fn list)
235   "Return the result of applying FN to the first 2 items in LIST,
236 then applying FN to that result and the 3rd item, etc. If LIST
237 contains no items, return the result of calling FN with no
238 arguments. If LIST contains a single item, return that item
239 and do not call FN.
240
241 In the anaphoric form `--reduce', the accumulated value is
242 exposed as symbol `acc'.
243
244 See also: `-reduce-from', `-reduce-r'"
245   (if list
246       (-reduce-from fn (car list) (cdr list))
247     (funcall fn)))
248
249 (defmacro --reduce-r-from (form initial-value list)
250   "Anaphoric version of `-reduce-r-from'."
251   (declare (debug (form form form)))
252   `(--reduce-from ,form ,initial-value (reverse ,list)))
253
254 (defun -reduce-r-from (fn initial-value list)
255   "Replace conses with FN, nil with INITIAL-VALUE and evaluate
256 the resulting expression. If LIST is empty, INITIAL-VALUE is
257 returned and FN is not called.
258
259 Note: this function works the same as `-reduce-from' but the
260 operation associates from right instead of from left.
261
262 See also: `-reduce-r', `-reduce'"
263   (--reduce-r-from (funcall fn it acc) initial-value list))
264
265 (defmacro --reduce-r (form list)
266   "Anaphoric version of `-reduce-r'."
267   (declare (debug (form form)))
268   `(--reduce ,form (reverse ,list)))
269
270 (defun -reduce-r (fn list)
271   "Replace conses with FN and evaluate the resulting expression.
272 The final nil is ignored. If LIST contains no items, return the
273 result of calling FN with no arguments. If LIST contains a single
274 item, return that item and do not call FN.
275
276 The first argument of FN is the new item, the second is the
277 accumulated value.
278
279 Note: this function works the same as `-reduce' but the operation
280 associates from right instead of from left.
281
282 See also: `-reduce-r-from', `-reduce'"
283   (if list
284       (--reduce-r (funcall fn it acc) list)
285     (funcall fn)))
286
287 (defun -reductions-from (fn init list)
288   "Return a list of the intermediate values of the reduction.
289
290 See `-reduce-from' for explanation of the arguments.
291
292 See also: `-reductions', `-reductions-r', `-reduce-r'"
293   (nreverse (--reduce-from (cons (funcall fn (car acc) it) acc) (list init) list)))
294
295 (defun -reductions (fn list)
296   "Return a list of the intermediate values of the reduction.
297
298 See `-reduce' for explanation of the arguments.
299
300 See also: `-reductions-from', `-reductions-r', `-reduce-r'"
301   (and list (-reductions-from fn (car list) (cdr list))))
302
303 (defun -reductions-r-from (fn init list)
304   "Return a list of the intermediate values of the reduction.
305
306 See `-reduce-r-from' for explanation of the arguments.
307
308 See also: `-reductions-r', `-reductions', `-reduce'"
309   (--reduce-r-from (cons (funcall fn it (car acc)) acc) (list init) list))
310
311 (defun -reductions-r (fn list)
312   "Return a list of the intermediate values of the reduction.
313
314 See `-reduce-r' for explanation of the arguments.
315
316 See also: `-reductions-r-from', `-reductions', `-reduce'"
317   (when list
318     (let ((rev (reverse list)))
319       (--reduce-from (cons (funcall fn it (car acc)) acc)
320                      (list (car rev))
321                      (cdr rev)))))
322
323 (defmacro --filter (form list)
324   "Anaphoric form of `-filter'.
325
326 See also: `--remove'."
327   (declare (debug (form form)))
328   (let ((r (make-symbol "result")))
329     `(let (,r)
330        (--each ,list (when ,form (!cons it ,r)))
331        (nreverse ,r))))
332
333 (defun -filter (pred list)
334   "Return a new list of the items in LIST for which PRED returns a non-nil value.
335
336 Alias: `-select'
337
338 See also: `-keep', `-remove'."
339   (--filter (funcall pred it) list))
340
341 (defalias '-select '-filter)
342 (defalias '--select '--filter)
343
344 (defmacro --remove (form list)
345   "Anaphoric form of `-remove'.
346
347 See also `--filter'."
348   (declare (debug (form form)))
349   `(--filter (not ,form) ,list))
350
351 (defun -remove (pred list)
352   "Return a new list of the items in LIST for which PRED returns nil.
353
354 Alias: `-reject'
355
356 See also: `-filter'."
357   (--remove (funcall pred it) list))
358
359 (defalias '-reject '-remove)
360 (defalias '--reject '--remove)
361
362 (defun -remove-first (pred list)
363   "Return a new list with the first item matching PRED removed.
364
365 Alias: `-reject-first'
366
367 See also: `-remove', `-map-first'"
368   (let (front)
369     (while (and list (not (funcall pred (car list))))
370       (push (car list) front)
371       (!cdr list))
372     (if list
373         (-concat (nreverse front) (cdr list))
374       (nreverse front))))
375
376 (defmacro --remove-first (form list)
377   "Anaphoric form of `-remove-first'."
378   (declare (debug (form form)))
379   `(-remove-first (lambda (it) ,form) ,list))
380
381 (defalias '-reject-first '-remove-first)
382 (defalias '--reject-first '--remove-first)
383
384 (defun -remove-last (pred list)
385   "Return a new list with the last item matching PRED removed.
386
387 Alias: `-reject-last'
388
389 See also: `-remove', `-map-last'"
390   (nreverse (-remove-first pred (reverse list))))
391
392 (defmacro --remove-last (form list)
393   "Anaphoric form of `-remove-last'."
394   (declare (debug (form form)))
395   `(-remove-last (lambda (it) ,form) ,list))
396
397 (defalias '-reject-last '-remove-last)
398 (defalias '--reject-last '--remove-last)
399
400 (defun -remove-item (item list)
401   "Remove all occurences of ITEM from LIST.
402
403 Comparison is done with `equal'."
404   (declare (pure t) (side-effect-free t))
405   (--remove (equal it item) list))
406
407 (defmacro --keep (form list)
408   "Anaphoric form of `-keep'."
409   (declare (debug (form form)))
410   (let ((r (make-symbol "result"))
411         (m (make-symbol "mapped")))
412     `(let (,r)
413        (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r))))
414        (nreverse ,r))))
415
416 (defun -keep (fn list)
417   "Return a new list of the non-nil results of applying FN to the items in LIST.
418
419 If you want to select the original items satisfying a predicate use `-filter'."
420   (--keep (funcall fn it) list))
421
422 (defun -non-nil (list)
423   "Return all non-nil elements of LIST."
424   (declare (pure t) (side-effect-free t))
425   (-remove 'null list))
426
427 (defmacro --map-indexed (form list)
428   "Anaphoric form of `-map-indexed'."
429   (declare (debug (form form)))
430   (let ((r (make-symbol "result")))
431     `(let (,r)
432        (--each ,list
433          (!cons ,form ,r))
434        (nreverse ,r))))
435
436 (defun -map-indexed (fn list)
437   "Return a new list consisting of the result of (FN index item) for each item in LIST.
438
439 In the anaphoric form `--map-indexed', the index is exposed as symbol `it-index'.
440
441 See also: `-each-indexed'."
442   (--map-indexed (funcall fn it-index it) list))
443
444 (defmacro --map-when (pred rep list)
445   "Anaphoric form of `-map-when'."
446   (declare (debug (form form form)))
447   (let ((r (make-symbol "result")))
448     `(let (,r)
449        (--each ,list (!cons (if ,pred ,rep it) ,r))
450        (nreverse ,r))))
451
452 (defun -map-when (pred rep list)
453   "Return a new list where the elements in LIST that do not match the PRED function
454 are unchanged, and where the elements in LIST that do match the PRED function are mapped
455 through the REP function.
456
457 Alias: `-replace-where'
458
459 See also: `-update-at'"
460   (--map-when (funcall pred it) (funcall rep it) list))
461
462 (defalias '-replace-where '-map-when)
463 (defalias '--replace-where '--map-when)
464
465 (defun -map-first (pred rep list)
466   "Replace first item in LIST satisfying PRED with result of REP called on this item.
467
468 See also: `-map-when', `-replace-first'"
469   (let (front)
470     (while (and list (not (funcall pred (car list))))
471       (push (car list) front)
472       (!cdr list))
473     (if list
474         (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list)))
475       (nreverse front))))
476
477 (defmacro --map-first (pred rep list)
478   "Anaphoric form of `-map-first'."
479   `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
480
481 (defun -map-last (pred rep list)
482   "Replace last item in LIST satisfying PRED with result of REP called on this item.
483
484 See also: `-map-when', `-replace-last'"
485   (nreverse (-map-first pred rep (reverse list))))
486
487 (defmacro --map-last (pred rep list)
488   "Anaphoric form of `-map-last'."
489   `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
490
491 (defun -replace (old new list)
492   "Replace all OLD items in LIST with NEW.
493
494 Elements are compared using `equal'.
495
496 See also: `-replace-at'"
497   (declare (pure t) (side-effect-free t))
498   (--map-when (equal it old) new list))
499
500 (defun -replace-first (old new list)
501   "Replace the first occurence of OLD with NEW in LIST.
502
503 Elements are compared using `equal'.
504
505 See also: `-map-first'"
506   (declare (pure t) (side-effect-free t))
507   (--map-first (equal old it) new list))
508
509 (defun -replace-last (old new list)
510   "Replace the last occurence of OLD with NEW in LIST.
511
512 Elements are compared using `equal'.
513
514 See also: `-map-last'"
515   (declare (pure t) (side-effect-free t))
516   (--map-last (equal old it) new list))
517
518 (defmacro --mapcat (form list)
519   "Anaphoric form of `-mapcat'."
520   (declare (debug (form form)))
521   `(apply 'append (--map ,form ,list)))
522
523 (defun -mapcat (fn list)
524   "Return the concatenation of the result of mapping FN over LIST.
525 Thus function FN should return a list."
526   (--mapcat (funcall fn it) list))
527
528 (defun -flatten (l)
529   "Take a nested list L and return its contents as a single, flat list.
530
531 Note that because `nil' represents a list of zero elements (an
532 empty list), any mention of nil in L will disappear after
533 flattening.  If you need to preserve nils, consider `-flatten-n'
534 or map them to some unique symbol and then map them back.
535
536 Conses of two atoms are considered \"terminals\", that is, they
537 aren't flattened further.
538
539 See also: `-flatten-n'"
540   (declare (pure t) (side-effect-free t))
541   (if (and (listp l) (listp (cdr l)))
542       (-mapcat '-flatten l)
543     (list l)))
544
545 (defmacro --iterate (form init n)
546   "Anaphoric version of `-iterate'."
547   (declare (debug (form form form)))
548   `(-iterate (lambda (it) ,form) ,init ,n))
549
550 (defun -flatten-n (num list)
551   "Flatten NUM levels of a nested LIST.
552
553 See also: `-flatten'"
554   (declare (pure t) (side-effect-free t))
555   (-last-item (--iterate (--mapcat (-list it) it) list (1+ num))))
556
557 (defun -concat (&rest lists)
558   "Return a new list with the concatenation of the elements in the supplied LISTS."
559   (declare (pure t) (side-effect-free t))
560   (apply 'append lists))
561
562 (defalias '-copy 'copy-sequence
563   "Create a shallow copy of LIST.
564
565 \(fn LIST)")
566
567 (defun -splice (pred fun list)
568   "Splice lists generated by FUN in place of elements matching PRED in LIST.
569
570 FUN takes the element matching PRED as input.
571
572 This function can be used as replacement for `,@' in case you
573 need to splice several lists at marked positions (for example
574 with keywords).
575
576 See also: `-splice-list', `-insert-at'"
577   (let (r)
578     (--each list
579       (if (funcall pred it)
580           (let ((new (funcall fun it)))
581             (--each new (!cons it r)))
582         (!cons it r)))
583     (nreverse r)))
584
585 (defmacro --splice (pred form list)
586   "Anaphoric form of `-splice'."
587   `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list))
588
589 (defun -splice-list (pred new-list list)
590   "Splice NEW-LIST in place of elements matching PRED in LIST.
591
592 See also: `-splice', `-insert-at'"
593   (-splice pred (lambda (_) new-list) list))
594
595 (defmacro --splice-list (pred new-list list)
596   "Anaphoric form of `-splice-list'."
597   `(-splice-list (lambda (it) ,pred) ,new-list ,list))
598
599 (defun -cons* (&rest args)
600   "Make a new list from the elements of ARGS.
601
602 The last 2 members of ARGS are used as the final cons of the
603 result so if the final member of ARGS is not a list the result is
604 a dotted list."
605   (declare (pure t) (side-effect-free t))
606   (-reduce-r 'cons args))
607
608 (defun -snoc (list elem &rest elements)
609   "Append ELEM to the end of the list.
610
611 This is like `cons', but operates on the end of list.
612
613 If ELEMENTS is non nil, append these to the list as well."
614   (-concat list (list elem) elements))
615
616 (defmacro --first (form list)
617   "Anaphoric form of `-first'."
618   (declare (debug (form form)))
619   (let ((n (make-symbol "needle")))
620     `(let (,n)
621        (--each-while ,list (not ,n)
622          (when ,form (setq ,n it)))
623        ,n)))
624
625 (defun -first (pred list)
626   "Return the first x in LIST where (PRED x) is non-nil, else nil.
627
628 To get the first item in the list no questions asked, use `car'.
629
630 Alias: `-find'"
631   (--first (funcall pred it) list))
632
633 (defalias '-find '-first)
634 (defalias '--find '--first)
635
636 (defmacro --some (form list)
637   "Anaphoric form of `-some'."
638   (declare (debug (form form)))
639   (let ((n (make-symbol "needle")))
640     `(let (,n)
641        (--each-while ,list (not ,n)
642          (setq ,n ,form))
643        ,n)))
644
645 (defun -some (pred list)
646   "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil.
647
648 Alias: `-any'"
649   (--some (funcall pred it) list))
650
651 (defalias '-any '-some)
652 (defalias '--any '--some)
653
654 (defmacro --last (form list)
655   "Anaphoric form of `-last'."
656   (declare (debug (form form)))
657   (let ((n (make-symbol "needle")))
658     `(let (,n)
659        (--each ,list
660          (when ,form (setq ,n it)))
661        ,n)))
662
663 (defun -last (pred list)
664   "Return the last x in LIST where (PRED x) is non-nil, else nil."
665   (--last (funcall pred it) list))
666
667 (defalias '-first-item 'car
668   "Return the first item of LIST, or nil on an empty list.
669
670 See also: `-second-item', `-last-item'.
671
672 \(fn LIST)")
673
674 ;; Ensure that calls to `-first-item' are compiled to a single opcode,
675 ;; just like `car'.
676 (put '-first-item 'byte-opcode 'byte-car)
677 (put '-first-item 'byte-compile 'byte-compile-one-arg)
678
679 (defalias '-second-item 'cadr
680   "Return the second item of LIST, or nil if LIST is too short.
681
682 See also: `-third-item'.
683
684 \(fn LIST)")
685
686 (defalias '-third-item 'caddr
687   "Return the third item of LIST, or nil if LIST is too short.
688
689 See also: `-fourth-item'.
690
691 \(fn LIST)")
692
693 (defun -fourth-item (list)
694   "Return the fourth item of LIST, or nil if LIST is too short.
695
696 See also: `-fifth-item'."
697   (declare (pure t) (side-effect-free t))
698   (car (cdr (cdr (cdr list)))))
699
700 (defun -fifth-item (list)
701   "Return the fifth item of LIST, or nil if LIST is too short.
702
703 See also: `-last-item'."
704   (declare (pure t) (side-effect-free t))
705   (car (cdr (cdr (cdr (cdr list))))))
706
707 ;; TODO: gv was introduced in 24.3, so we can remove the if statement
708 ;; when support for earlier versions is dropped
709 (eval-when-compile
710   (require 'cl)
711   (if (fboundp 'gv-define-simple-setter)
712       (gv-define-simple-setter -first-item setcar)
713     (require 'cl)
714     (with-no-warnings
715       (defsetf -first-item (x) (val) `(setcar ,x ,val)))))
716
717 (defun -last-item (list)
718   "Return the last item of LIST, or nil on an empty list."
719   (declare (pure t) (side-effect-free t))
720   (car (last list)))
721
722 ;; TODO: gv was introduced in 24.3, so we can remove the if statement
723 ;; when support for earlier versions is dropped
724 (eval-when-compile
725   (if (fboundp 'gv-define-setter)
726       (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val))
727     (with-no-warnings
728       (defsetf -last-item (x) (val) `(setcar (last ,x) ,val)))))
729
730 (defun -butlast (list)
731   "Return a list of all items in list except for the last."
732   ;; no alias as we don't want magic optional argument
733   (declare (pure t) (side-effect-free t))
734   (butlast list))
735
736 (defmacro --count (pred list)
737   "Anaphoric form of `-count'."
738   (declare (debug (form form)))
739   (let ((r (make-symbol "result")))
740     `(let ((,r 0))
741        (--each ,list (when ,pred (setq ,r (1+ ,r))))
742        ,r)))
743
744 (defun -count (pred list)
745   "Counts the number of items in LIST where (PRED item) is non-nil."
746   (--count (funcall pred it) list))
747
748 (defun ---truthy? (val)
749   (declare (pure t) (side-effect-free t))
750   (not (null val)))
751
752 (defmacro --any? (form list)
753   "Anaphoric form of `-any?'."
754   (declare (debug (form form)))
755   `(---truthy? (--some ,form ,list)))
756
757 (defun -any? (pred list)
758   "Return t if (PRED x) is non-nil for any x in LIST, else nil.
759
760 Alias: `-any-p', `-some?', `-some-p'"
761   (--any? (funcall pred it) list))
762
763 (defalias '-some? '-any?)
764 (defalias '--some? '--any?)
765 (defalias '-any-p '-any?)
766 (defalias '--any-p '--any?)
767 (defalias '-some-p '-any?)
768 (defalias '--some-p '--any?)
769
770 (defmacro --all? (form list)
771   "Anaphoric form of `-all?'."
772   (declare (debug (form form)))
773   (let ((a (make-symbol "all")))
774     `(let ((,a t))
775        (--each-while ,list ,a (setq ,a ,form))
776        (---truthy? ,a))))
777
778 (defun -all? (pred list)
779   "Return t if (PRED x) is non-nil for all x in LIST, else nil.
780
781 Alias: `-all-p', `-every?', `-every-p'"
782   (--all? (funcall pred it) list))
783
784 (defalias '-every? '-all?)
785 (defalias '--every? '--all?)
786 (defalias '-all-p '-all?)
787 (defalias '--all-p '--all?)
788 (defalias '-every-p '-all?)
789 (defalias '--every-p '--all?)
790
791 (defmacro --none? (form list)
792   "Anaphoric form of `-none?'."
793   (declare (debug (form form)))
794   `(--all? (not ,form) ,list))
795
796 (defun -none? (pred list)
797   "Return t if (PRED x) is nil for all x in LIST, else nil.
798
799 Alias: `-none-p'"
800   (--none? (funcall pred it) list))
801
802 (defalias '-none-p '-none?)
803 (defalias '--none-p '--none?)
804
805 (defmacro --only-some? (form list)
806   "Anaphoric form of `-only-some?'."
807   (declare (debug (form form)))
808   (let ((y (make-symbol "yes"))
809         (n (make-symbol "no")))
810     `(let (,y ,n)
811        (--each-while ,list (not (and ,y ,n))
812          (if ,form (setq ,y t) (setq ,n t)))
813        (---truthy? (and ,y ,n)))))
814
815 (defun -only-some? (pred list)
816   "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED.
817 Return `nil` both if all items match the predicate or if none of the items match the predicate.
818
819 Alias: `-only-some-p'"
820   (--only-some? (funcall pred it) list))
821
822 (defalias '-only-some-p '-only-some?)
823 (defalias '--only-some-p '--only-some?)
824
825 (defun -slice (list from &optional to step)
826   "Return copy of LIST, starting from index FROM to index TO.
827
828 FROM or TO may be negative.  These values are then interpreted
829 modulo the length of the list.
830
831 If STEP is a number, only each STEPth item in the resulting
832 section is returned.  Defaults to 1."
833   (declare (pure t) (side-effect-free t))
834   (let ((length (length list))
835         (new-list nil))
836     ;; to defaults to the end of the list
837     (setq to (or to length))
838     (setq step (or step 1))
839     ;; handle negative indices
840     (when (< from 0)
841       (setq from (mod from length)))
842     (when (< to 0)
843       (setq to (mod to length)))
844
845     ;; iterate through the list, keeping the elements we want
846     (--each-while list (< it-index to)
847       (when (and (>= it-index from)
848                  (= (mod (- from it-index) step) 0))
849         (push it new-list)))
850     (nreverse new-list)))
851
852 (defun -take (n list)
853   "Return a new list of the first N items in LIST, or all items if there are fewer than N.
854
855 See also: `-take-last'"
856   (declare (pure t) (side-effect-free t))
857   (let (result)
858     (--dotimes n
859       (when list
860         (!cons (car list) result)
861         (!cdr list)))
862     (nreverse result)))
863
864 (defun -take-last (n list)
865   "Return the last N items of LIST in order.
866
867 See also: `-take'"
868   (declare (pure t) (side-effect-free t))
869   (copy-sequence (last list n)))
870
871 (defalias '-drop 'nthcdr
872   "Return the tail of LIST without the first N items.
873
874 See also: `-drop-last'
875
876 \(fn N LIST)")
877
878 (defun -drop-last (n list)
879   "Remove the last N items of LIST and return a copy.
880
881 See also: `-drop'"
882   ;; No alias because we don't want magic optional argument
883   (declare (pure t) (side-effect-free t))
884   (butlast list n))
885
886 (defmacro --take-while (form list)
887   "Anaphoric form of `-take-while'."
888   (declare (debug (form form)))
889   (let ((r (make-symbol "result")))
890     `(let (,r)
891        (--each-while ,list ,form (!cons it ,r))
892        (nreverse ,r))))
893
894 (defun -take-while (pred list)
895   "Return a new list of successive items from LIST while (PRED item) returns a non-nil value."
896   (--take-while (funcall pred it) list))
897
898 (defmacro --drop-while (form list)
899   "Anaphoric form of `-drop-while'."
900   (declare (debug (form form)))
901   (let ((l (make-symbol "list")))
902     `(let ((,l ,list))
903        (while (and ,l (let ((it (car ,l))) ,form))
904          (!cdr ,l))
905        ,l)))
906
907 (defun -drop-while (pred list)
908   "Return the tail of LIST starting from the first item for which (PRED item) returns nil."
909   (--drop-while (funcall pred it) list))
910
911 (defun -split-at (n list)
912   "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list."
913   (declare (pure t) (side-effect-free t))
914   (let (result)
915     (--dotimes n
916       (when list
917         (!cons (car list) result)
918         (!cdr list)))
919     (list (nreverse result) list)))
920
921 (defun -rotate (n list)
922   "Rotate LIST N places to the right.  With N negative, rotate to the left.
923 The time complexity is O(n)."
924   (declare (pure t) (side-effect-free t))
925   (when list
926     (let* ((len (length list))
927            (n-mod-len (mod n len))
928            (new-tail-len (- len n-mod-len)))
929       (append (-drop new-tail-len list) (-take new-tail-len list)))))
930
931 (defun -insert-at (n x list)
932   "Return a list with X inserted into LIST at position N.
933
934 See also: `-splice', `-splice-list'"
935   (declare (pure t) (side-effect-free t))
936   (let ((split-list (-split-at n list)))
937     (nconc (car split-list) (cons x (cadr split-list)))))
938
939 (defun -replace-at (n x list)
940   "Return a list with element at Nth position in LIST replaced with X.
941
942 See also: `-replace'"
943   (declare (pure t) (side-effect-free t))
944   (let ((split-list (-split-at n list)))
945     (nconc (car split-list) (cons x (cdr (cadr split-list))))))
946
947 (defun -update-at (n func list)
948   "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.
949
950 See also: `-map-when'"
951   (let ((split-list (-split-at n list)))
952     (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list))))))
953
954 (defmacro --update-at (n form list)
955   "Anaphoric version of `-update-at'."
956   (declare (debug (form form form)))
957   `(-update-at ,n (lambda (it) ,form) ,list))
958
959 (defun -remove-at (n list)
960   "Return a list with element at Nth position in LIST removed.
961
962 See also: `-remove-at-indices', `-remove'"
963   (declare (pure t) (side-effect-free t))
964   (-remove-at-indices (list n) list))
965
966 (defun -remove-at-indices (indices list)
967   "Return a list whose elements are elements from LIST without
968 elements selected as `(nth i list)` for all i
969 from INDICES.
970
971 See also: `-remove-at', `-remove'"
972   (declare (pure t) (side-effect-free t))
973   (let* ((indices (-sort '< indices))
974          (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices))))
975          r)
976     (--each diffs
977       (let ((split (-split-at it list)))
978         (!cons (car split) r)
979         (setq list (cdr (cadr split)))))
980     (!cons list r)
981     (apply '-concat (nreverse r))))
982
983 (defmacro --split-with (pred list)
984   "Anaphoric form of `-split-with'."
985   (declare (debug (form form)))
986   (let ((l (make-symbol "list"))
987         (r (make-symbol "result"))
988         (c (make-symbol "continue")))
989     `(let ((,l ,list)
990            (,r nil)
991            (,c t))
992        (while (and ,l ,c)
993          (let ((it (car ,l)))
994            (if (not ,pred)
995                (setq ,c nil)
996              (!cons it ,r)
997              (!cdr ,l))))
998        (list (nreverse ,r) ,l))))
999
1000 (defun -split-with (pred list)
1001   "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list."
1002   (--split-with (funcall pred it) list))
1003
1004 (defmacro -split-on (item list)
1005   "Split the LIST each time ITEM is found.
1006
1007 Unlike `-partition-by', the ITEM is discarded from the results.
1008 Empty lists are also removed from the result.
1009
1010 Comparison is done by `equal'.
1011
1012 See also `-split-when'"
1013   (declare (debug (form form)))
1014   `(-split-when (lambda (it) (equal it ,item)) ,list))
1015
1016 (defmacro --split-when (form list)
1017   "Anaphoric version of `-split-when'."
1018   (declare (debug (form form)))
1019   `(-split-when (lambda (it) ,form) ,list))
1020
1021 (defun -split-when (fn list)
1022   "Split the LIST on each element where FN returns non-nil.
1023
1024 Unlike `-partition-by', the \"matched\" element is discarded from
1025 the results.  Empty lists are also removed from the result.
1026
1027 This function can be thought of as a generalization of
1028 `split-string'."
1029   (let (r s)
1030     (while list
1031       (if (not (funcall fn (car list)))
1032           (push (car list) s)
1033         (when s (push (nreverse s) r))
1034         (setq s nil))
1035       (!cdr list))
1036     (when s (push (nreverse s) r))
1037     (nreverse r)))
1038
1039 (defmacro --separate (form list)
1040   "Anaphoric form of `-separate'."
1041   (declare (debug (form form)))
1042   (let ((y (make-symbol "yes"))
1043         (n (make-symbol "no")))
1044     `(let (,y ,n)
1045        (--each ,list (if ,form (!cons it ,y) (!cons it ,n)))
1046        (list (nreverse ,y) (nreverse ,n)))))
1047
1048 (defun -separate (pred list)
1049   "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list."
1050   (--separate (funcall pred it) list))
1051
1052 (defun ---partition-all-in-steps-reversed (n step list)
1053   "Private: Used by -partition-all-in-steps and -partition-in-steps."
1054   (when (< step 1)
1055     (error "Step must be a positive number, or you're looking at some juicy infinite loops."))
1056   (let ((result nil))
1057     (while list
1058       (!cons (-take n list) result)
1059       (setq list (-drop step list)))
1060     result))
1061
1062 (defun -partition-all-in-steps (n step list)
1063   "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
1064 The last groups may contain less than N items."
1065   (declare (pure t) (side-effect-free t))
1066   (nreverse (---partition-all-in-steps-reversed n step list)))
1067
1068 (defun -partition-in-steps (n step list)
1069   "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
1070 If there are not enough items to make the last group N-sized,
1071 those items are discarded."
1072   (declare (pure t) (side-effect-free t))
1073   (let ((result (---partition-all-in-steps-reversed n step list)))
1074     (while (and result (< (length (car result)) n))
1075       (!cdr result))
1076     (nreverse result)))
1077
1078 (defun -partition-all (n list)
1079   "Return a new list with the items in LIST grouped into N-sized sublists.
1080 The last group may contain less than N items."
1081   (declare (pure t) (side-effect-free t))
1082   (-partition-all-in-steps n n list))
1083
1084 (defun -partition (n list)
1085   "Return a new list with the items in LIST grouped into N-sized sublists.
1086 If there are not enough items to make the last group N-sized,
1087 those items are discarded."
1088   (declare (pure t) (side-effect-free t))
1089   (-partition-in-steps n n list))
1090
1091 (defmacro --partition-by (form list)
1092   "Anaphoric form of `-partition-by'."
1093   (declare (debug (form form)))
1094   (let ((r (make-symbol "result"))
1095         (s (make-symbol "sublist"))
1096         (v (make-symbol "value"))
1097         (n (make-symbol "new-value"))
1098         (l (make-symbol "list")))
1099     `(let ((,l ,list))
1100        (when ,l
1101          (let* ((,r nil)
1102                 (it (car ,l))
1103                 (,s (list it))
1104                 (,v ,form)
1105                 (,l (cdr ,l)))
1106            (while ,l
1107              (let* ((it (car ,l))
1108                     (,n ,form))
1109                (unless (equal ,v ,n)
1110                  (!cons (nreverse ,s) ,r)
1111                  (setq ,s nil)
1112                  (setq ,v ,n))
1113                (!cons it ,s)
1114                (!cdr ,l)))
1115            (!cons (nreverse ,s) ,r)
1116            (nreverse ,r))))))
1117
1118 (defun -partition-by (fn list)
1119   "Apply FN to each item in LIST, splitting it each time FN returns a new value."
1120   (--partition-by (funcall fn it) list))
1121
1122 (defmacro --partition-by-header (form list)
1123   "Anaphoric form of `-partition-by-header'."
1124   (declare (debug (form form)))
1125   (let ((r (make-symbol "result"))
1126         (s (make-symbol "sublist"))
1127         (h (make-symbol "header-value"))
1128         (b (make-symbol "seen-body?"))
1129         (n (make-symbol "new-value"))
1130         (l (make-symbol "list")))
1131     `(let ((,l ,list))
1132        (when ,l
1133          (let* ((,r nil)
1134                 (it (car ,l))
1135                 (,s (list it))
1136                 (,h ,form)
1137                 (,b nil)
1138                 (,l (cdr ,l)))
1139            (while ,l
1140              (let* ((it (car ,l))
1141                     (,n ,form))
1142                (if (equal ,h ,n)
1143                    (when ,b
1144                      (!cons (nreverse ,s) ,r)
1145                      (setq ,s nil)
1146                      (setq ,b nil))
1147                  (setq ,b t))
1148                (!cons it ,s)
1149                (!cdr ,l)))
1150            (!cons (nreverse ,s) ,r)
1151            (nreverse ,r))))))
1152
1153 (defun -partition-by-header (fn list)
1154   "Apply FN to the first item in LIST. That is the header
1155 value. Apply FN to each item in LIST, splitting it each time FN
1156 returns the header value, but only after seeing at least one
1157 other value (the body)."
1158   (--partition-by-header (funcall fn it) list))
1159
1160 (defun -partition-after-pred (pred list)
1161   "Partition directly after each time PRED is true on an element of LIST."
1162   (when list
1163     (let ((rest (-partition-after-pred pred
1164                                        (cdr list))))
1165       (if (funcall pred (car list))
1166           ;;split after (car list)
1167           (cons (list (car list))
1168                 rest)
1169
1170         ;;don't split after (car list)
1171         (cons (cons (car list)
1172                     (car rest))
1173               (cdr rest))))))
1174
1175 (defun -partition-before-pred (pred list)
1176   "Partition directly before each time PRED is true on an element of LIST."
1177   (nreverse (-map #'reverse
1178                   (-partition-after-pred pred (reverse list)))))
1179
1180 (defun -partition-after-item (item list)
1181   "Partition directly after each time ITEM appears in LIST."
1182   (-partition-after-pred (lambda (ele) (equal ele item))
1183                          list))
1184
1185 (defun -partition-before-item (item list)
1186   "Partition directly before each time ITEM appears in LIST."
1187   (-partition-before-pred (lambda (ele) (equal ele item))
1188                           list))
1189
1190 (defmacro --group-by (form list)
1191   "Anaphoric form of `-group-by'."
1192   (declare (debug t))
1193   (let ((n (make-symbol "n"))
1194         (k (make-symbol "k"))
1195         (grp (make-symbol "grp")))
1196     `(nreverse
1197       (-map
1198        (lambda (,n)
1199          (cons (car ,n)
1200                (nreverse (cdr ,n))))
1201        (--reduce-from
1202         (let* ((,k (,@form))
1203                (,grp (assoc ,k acc)))
1204           (if ,grp
1205               (setcdr ,grp (cons it (cdr ,grp)))
1206             (push
1207              (list ,k it)
1208              acc))
1209           acc)
1210         nil ,list)))))
1211
1212 (defun -group-by (fn list)
1213   "Separate LIST into an alist whose keys are FN applied to the
1214 elements of LIST.  Keys are compared by `equal'."
1215   (--group-by (funcall fn it) list))
1216
1217 (defun -interpose (sep list)
1218   "Return a new list of all elements in LIST separated by SEP."
1219   (declare (pure t) (side-effect-free t))
1220   (let (result)
1221     (when list
1222       (!cons (car list) result)
1223       (!cdr list))
1224     (while list
1225       (setq result (cons (car list) (cons sep result)))
1226       (!cdr list))
1227     (nreverse result)))
1228
1229 (defun -interleave (&rest lists)
1230   "Return a new list of the first item in each list, then the second etc."
1231   (declare (pure t) (side-effect-free t))
1232   (when lists
1233     (let (result)
1234       (while (-none? 'null lists)
1235         (--each lists (!cons (car it) result))
1236         (setq lists (-map 'cdr lists)))
1237       (nreverse result))))
1238
1239 (defmacro --zip-with (form list1 list2)
1240   "Anaphoric form of `-zip-with'.
1241
1242 The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'."
1243   (declare (debug (form form form)))
1244   (let ((r (make-symbol "result"))
1245         (l1 (make-symbol "list1"))
1246         (l2 (make-symbol "list2")))
1247     `(let ((,r nil)
1248            (,l1 ,list1)
1249            (,l2 ,list2))
1250        (while (and ,l1 ,l2)
1251          (let ((it (car ,l1))
1252                (other (car ,l2)))
1253            (!cons ,form ,r)
1254            (!cdr ,l1)
1255            (!cdr ,l2)))
1256        (nreverse ,r))))
1257
1258 (defun -zip-with (fn list1 list2)
1259   "Zip the two lists LIST1 and LIST2 using a function FN.  This
1260 function is applied pairwise taking as first argument element of
1261 LIST1 and as second argument element of LIST2 at corresponding
1262 position.
1263
1264 The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it',
1265 and the elements from LIST2 as symbol `other'."
1266   (--zip-with (funcall fn it other) list1 list2))
1267
1268 (defun -zip (&rest lists)
1269   "Zip LISTS together.  Group the head of each list, followed by the
1270 second elements of each list, and so on. The lengths of the returned
1271 groupings are equal to the length of the shortest input list.
1272
1273 If two lists are provided as arguments, return the groupings as a list
1274 of cons cells. Otherwise, return the groupings as a list of lists.
1275
1276 Please note! This distinction is being removed in an upcoming 3.0
1277 release of Dash. If you rely on this behavior, use -zip-pair instead."
1278   (declare (pure t) (side-effect-free t))
1279   (when lists
1280     (let (results)
1281       (while (-none? 'null lists)
1282         (setq results (cons (mapcar 'car lists) results))
1283         (setq lists (mapcar 'cdr lists)))
1284       (setq results (nreverse results))
1285       (if (= (length lists) 2)
1286           ;; to support backward compatability, return
1287           ;; a cons cell if two lists were provided
1288           (--map (cons (car it) (cadr it)) results)
1289         results))))
1290
1291 (defalias '-zip-pair '-zip)
1292
1293 (defun -zip-fill (fill-value &rest lists)
1294   "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
1295 lengths of the returned groupings are equal to the length of the
1296 longest input list."
1297   (declare (pure t) (side-effect-free t))
1298   (apply '-zip (apply '-pad (cons fill-value lists))))
1299
1300 (defun -unzip (lists)
1301   "Unzip LISTS.
1302
1303 This works just like `-zip' but takes a list of lists instead of
1304 a variable number of arguments, such that
1305
1306   (-unzip (-zip L1 L2 L3 ...))
1307
1308 is identity (given that the lists are the same length).
1309
1310 See also: `-zip'"
1311   (apply '-zip lists))
1312
1313 (defun -cycle (list)
1314   "Return an infinite copy of LIST that will cycle through the
1315 elements and repeat from the beginning."
1316   (declare (pure t) (side-effect-free t))
1317   (let ((newlist (-map 'identity list)))
1318     (nconc newlist newlist)))
1319
1320 (defun -pad (fill-value &rest lists)
1321   "Appends FILL-VALUE to the end of each list in LISTS such that they
1322 will all have the same length."
1323   (let* ((annotations (-annotate 'length lists))
1324          (n (-max (-map 'car annotations))))
1325     (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations)))
1326
1327 (defun -annotate (fn list)
1328   "Return a list of cons cells where each cell is FN applied to each
1329 element of LIST paired with the unmodified element of LIST."
1330   (-zip (-map fn list) list))
1331
1332 (defmacro --annotate (form list)
1333   "Anaphoric version of `-annotate'."
1334   (declare (debug (form form)))
1335   `(-annotate (lambda (it) ,form) ,list))
1336
1337 (defun dash--table-carry (lists restore-lists &optional re)
1338   "Helper for `-table' and `-table-flat'.
1339
1340 If a list overflows, carry to the right and reset the list."
1341   (while (not (or (car lists)
1342                   (equal lists '(nil))))
1343     (setcar lists (car restore-lists))
1344     (pop (cadr lists))
1345     (!cdr lists)
1346     (!cdr restore-lists)
1347     (when re
1348       (push (nreverse (car re)) (cadr re))
1349       (setcar re nil)
1350       (!cdr re))))
1351
1352 (defun -table (fn &rest lists)
1353   "Compute outer product of LISTS using function FN.
1354
1355 The function FN should have the same arity as the number of
1356 supplied lists.
1357
1358 The outer product is computed by applying fn to all possible
1359 combinations created by taking one element from each list in
1360 order.  The dimension of the result is (length lists).
1361
1362 See also: `-table-flat'"
1363   (let ((restore-lists (copy-sequence lists))
1364         (last-list (last lists))
1365         (re (make-list (length lists) nil)))
1366     (while (car last-list)
1367       (let ((item (apply fn (-map 'car lists))))
1368         (push item (car re))
1369         (setcar lists (cdar lists)) ;; silence byte compiler
1370         (dash--table-carry lists restore-lists re)))
1371     (nreverse (car (last re)))))
1372
1373 (defun -table-flat (fn &rest lists)
1374   "Compute flat outer product of LISTS using function FN.
1375
1376 The function FN should have the same arity as the number of
1377 supplied lists.
1378
1379 The outer product is computed by applying fn to all possible
1380 combinations created by taking one element from each list in
1381 order.  The results are flattened, ignoring the tensor structure
1382 of the result.  This is equivalent to calling:
1383
1384   (-flatten-n (1- (length lists)) (apply \\='-table fn lists))
1385
1386 but the implementation here is much more efficient.
1387
1388 See also: `-flatten-n', `-table'"
1389   (let ((restore-lists (copy-sequence lists))
1390         (last-list (last lists))
1391         re)
1392     (while (car last-list)
1393       (let ((item (apply fn (-map 'car lists))))
1394         (push item re)
1395         (setcar lists (cdar lists)) ;; silence byte compiler
1396         (dash--table-carry lists restore-lists)))
1397     (nreverse re)))
1398
1399 (defun -partial (fn &rest args)
1400   "Take a function FN and fewer than the normal arguments to FN,
1401 and return a fn that takes a variable number of additional ARGS.
1402 When called, the returned function calls FN with ARGS first and
1403 then additional args."
1404   (apply 'apply-partially fn args))
1405
1406 (defun -elem-index (elem list)
1407   "Return the index of the first element in the given LIST which
1408 is equal to the query element ELEM, or nil if there is no
1409 such element."
1410   (declare (pure t) (side-effect-free t))
1411   (car (-elem-indices elem list)))
1412
1413 (defun -elem-indices (elem list)
1414   "Return the indices of all elements in LIST equal to the query
1415 element ELEM, in ascending order."
1416   (declare (pure t) (side-effect-free t))
1417   (-find-indices (-partial 'equal elem) list))
1418
1419 (defun -find-indices (pred list)
1420   "Return the indices of all elements in LIST satisfying the
1421 predicate PRED, in ascending order."
1422   (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list)))
1423
1424 (defmacro --find-indices (form list)
1425   "Anaphoric version of `-find-indices'."
1426   (declare (debug (form form)))
1427   `(-find-indices (lambda (it) ,form) ,list))
1428
1429 (defun -find-index (pred list)
1430   "Take a predicate PRED and a LIST and return the index of the
1431 first element in the list satisfying the predicate, or nil if
1432 there is no such element.
1433
1434 See also `-first'."
1435   (car (-find-indices pred list)))
1436
1437 (defmacro --find-index (form list)
1438   "Anaphoric version of `-find-index'."
1439   (declare (debug (form form)))
1440   `(-find-index (lambda (it) ,form) ,list))
1441
1442 (defun -find-last-index (pred list)
1443   "Take a predicate PRED and a LIST and return the index of the
1444 last element in the list satisfying the predicate, or nil if
1445 there is no such element.
1446
1447 See also `-last'."
1448   (-last-item (-find-indices pred list)))
1449
1450 (defmacro --find-last-index (form list)
1451   "Anaphoric version of `-find-last-index'."
1452   `(-find-last-index (lambda (it) ,form) ,list))
1453
1454 (defun -select-by-indices (indices list)
1455   "Return a list whose elements are elements from LIST selected
1456 as `(nth i list)` for all i from INDICES."
1457   (declare (pure t) (side-effect-free t))
1458   (let (r)
1459     (--each indices
1460       (!cons (nth it list) r))
1461     (nreverse r)))
1462
1463 (defun -select-columns (columns table)
1464   "Select COLUMNS from TABLE.
1465
1466 TABLE is a list of lists where each element represents one row.
1467 It is assumed each row has the same length.
1468
1469 Each row is transformed such that only the specified COLUMNS are
1470 selected.
1471
1472 See also: `-select-column', `-select-by-indices'"
1473   (declare (pure t) (side-effect-free t))
1474   (--map (-select-by-indices columns it) table))
1475
1476 (defun -select-column (column table)
1477   "Select COLUMN from TABLE.
1478
1479 TABLE is a list of lists where each element represents one row.
1480 It is assumed each row has the same length.
1481
1482 The single selected column is returned as a list.
1483
1484 See also: `-select-columns', `-select-by-indices'"
1485   (declare (pure t) (side-effect-free t))
1486   (--mapcat (-select-by-indices (list column) it) table))
1487
1488 (defmacro -> (x &optional form &rest more)
1489   "Thread the expr through the forms. Insert X as the second item
1490 in the first form, making a list of it if it is not a list
1491 already. If there are more forms, insert the first form as the
1492 second item in second form, etc."
1493   (declare (debug (form &rest [&or symbolp (sexp &rest form)])))
1494   (cond
1495    ((null form) x)
1496    ((null more) (if (listp form)
1497                     `(,(car form) ,x ,@(cdr form))
1498                   (list form x)))
1499    (:else `(-> (-> ,x ,form) ,@more))))
1500
1501 (defmacro ->> (x &optional form &rest more)
1502   "Thread the expr through the forms. Insert X as the last item
1503 in the first form, making a list of it if it is not a list
1504 already. If there are more forms, insert the first form as the
1505 last item in second form, etc."
1506   (declare (debug ->))
1507   (cond
1508    ((null form) x)
1509    ((null more) (if (listp form)
1510                     `(,@form ,x)
1511                   (list form x)))
1512    (:else `(->> (->> ,x ,form) ,@more))))
1513
1514 (defmacro --> (x &rest forms)
1515   "Starting with the value of X, thread each expression through FORMS.
1516
1517 Insert X at the position signified by the symbol `it' in the first
1518 form.  If there are more forms, insert the first form at the position
1519 signified by `it' in in second form, etc."
1520   (declare (debug (form body)))
1521   `(-as-> ,x it ,@forms))
1522
1523 (defmacro -as-> (value variable &rest forms)
1524   "Starting with VALUE, thread VARIABLE through FORMS.
1525
1526 In the first form, bind VARIABLE to VALUE.  In the second form, bind
1527 VARIABLE to the result of the first form, and so forth."
1528   (declare (debug (form symbolp body)))
1529   (if (null forms)
1530       `,value
1531     `(let ((,variable ,value))
1532        (-as-> ,(if (symbolp (car forms))
1533                  (list (car forms) variable)
1534                (car forms))
1535             ,variable
1536               ,@(cdr forms)))))
1537
1538 (defmacro -some-> (x &optional form &rest more)
1539   "When expr is non-nil, thread it through the first form (via `->'),
1540 and when that result is non-nil, through the next form, etc."
1541   (declare (debug ->))
1542   (if (null form) x
1543     (let ((result (make-symbol "result")))
1544       `(-some-> (-when-let (,result ,x)
1545                   (-> ,result ,form))
1546                 ,@more))))
1547
1548 (defmacro -some->> (x &optional form &rest more)
1549   "When expr is non-nil, thread it through the first form (via `->>'),
1550 and when that result is non-nil, through the next form, etc."
1551   (declare (debug ->))
1552   (if (null form) x
1553     (let ((result (make-symbol "result")))
1554       `(-some->> (-when-let (,result ,x)
1555                    (->> ,result ,form))
1556                  ,@more))))
1557
1558 (defmacro -some--> (x &optional form &rest more)
1559   "When expr in non-nil, thread it through the first form (via `-->'),
1560 and when that result is non-nil, through the next form, etc."
1561   (declare (debug ->))
1562   (if (null form) x
1563     (let ((result (make-symbol "result")))
1564       `(-some--> (-when-let (,result ,x)
1565                    (--> ,result ,form))
1566                  ,@more))))
1567
1568 (defun -grade-up (comparator list)
1569   "Grade elements of LIST using COMPARATOR relation, yielding a
1570 permutation vector such that applying this permutation to LIST
1571 sorts it in ascending order."
1572   ;; ugly hack to "fix" lack of lexical scope
1573   (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other)))))
1574     (->> (--map-indexed (cons it it-index) list)
1575          (-sort comp)
1576          (-map 'cdr))))
1577
1578 (defun -grade-down (comparator list)
1579   "Grade elements of LIST using COMPARATOR relation, yielding a
1580 permutation vector such that applying this permutation to LIST
1581 sorts it in descending order."
1582   ;; ugly hack to "fix" lack of lexical scope
1583   (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it)))))
1584     (->> (--map-indexed (cons it it-index) list)
1585          (-sort comp)
1586          (-map 'cdr))))
1587
1588 (defvar dash--source-counter 0
1589   "Monotonic counter for generated symbols.")
1590
1591 (defun dash--match-make-source-symbol ()
1592   "Generate a new dash-source symbol.
1593
1594 All returned symbols are guaranteed to be unique."
1595   (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter))
1596     (setq dash--source-counter (1+ dash--source-counter))))
1597
1598 (defun dash--match-ignore-place-p (symbol)
1599   "Return non-nil if SYMBOL is a symbol and starts with _."
1600   (and (symbolp symbol)
1601        (eq (aref (symbol-name symbol) 0) ?_)))
1602
1603 (defun dash--match-cons-skip-cdr (skip-cdr source)
1604   "Helper function generating idiomatic shifting code."
1605   (cond
1606    ((= skip-cdr 0)
1607     `(pop ,source))
1608    (t
1609     `(prog1 ,(dash--match-cons-get-car skip-cdr source)
1610        (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source))))))
1611
1612 (defun dash--match-cons-get-car (skip-cdr source)
1613   "Helper function generating idiomatic code to get nth car."
1614   (cond
1615    ((= skip-cdr 0)
1616     `(car ,source))
1617    ((= skip-cdr 1)
1618     `(cadr ,source))
1619    (t
1620     `(nth ,skip-cdr ,source))))
1621
1622 (defun dash--match-cons-get-cdr (skip-cdr source)
1623   "Helper function generating idiomatic code to get nth cdr."
1624   (cond
1625    ((= skip-cdr 0)
1626     source)
1627    ((= skip-cdr 1)
1628     `(cdr ,source))
1629    (t
1630     `(nthcdr ,skip-cdr ,source))))
1631
1632 (defun dash--match-cons (match-form source)
1633   "Setup a cons matching environment and call the real matcher."
1634   (let ((s (dash--match-make-source-symbol))
1635         (n 0)
1636         (m match-form))
1637     (while (and (consp m)
1638                 (dash--match-ignore-place-p (car m)))
1639       (setq n (1+ n)) (!cdr m))
1640     (cond
1641      ;; when we only have one pattern in the list, we don't have to
1642      ;; create a temporary binding (--dash-source--) for the source
1643      ;; and just use the input directly
1644      ((and (consp m)
1645            (not (cdr m)))
1646       (dash--match (car m) (dash--match-cons-get-car n source)))
1647      ;; handle other special types
1648      ((> n 0)
1649       (dash--match m (dash--match-cons-get-cdr n source)))
1650      ;; this is the only entry-point for dash--match-cons-1, that's
1651      ;; why we can't simply use the above branch, it would produce
1652      ;; infinite recursion
1653      (t
1654       (cons (list s source) (dash--match-cons-1 match-form s))))))
1655
1656 (defun dash--get-expand-function (type)
1657   "Get expand function name for TYPE."
1658   (intern (format "dash-expand:%s" type)))
1659
1660 (defun dash--match-cons-1 (match-form source &optional props)
1661   "Match MATCH-FORM against SOURCE.
1662
1663 MATCH-FORM is a proper or improper list.  Each element of
1664 MATCH-FORM is either a symbol, which gets bound to the respective
1665 value in source or another match form which gets destructured
1666 recursively.
1667
1668 If the cdr of last cons cell in the list is `nil', matching stops
1669 there.
1670
1671 SOURCE is a proper or improper list."
1672   (let ((skip-cdr (or (plist-get props :skip-cdr) 0)))
1673     (cond
1674      ((consp match-form)
1675       (cond
1676        ((cdr match-form)
1677         (cond
1678          ((and (symbolp (car match-form))
1679                (functionp (dash--get-expand-function (car match-form))))
1680           (dash--match-kv (dash--match-kv-normalize-match-form match-form) (dash--match-cons-get-cdr skip-cdr source)))
1681          ((dash--match-ignore-place-p (car match-form))
1682           (dash--match-cons-1 (cdr match-form) source
1683                               (plist-put props :skip-cdr (1+ skip-cdr))))
1684          (t
1685           (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source))
1686                    (dash--match-cons-1 (cdr match-form) source)))))
1687        (t ;; Last matching place, no need for shift
1688         (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source)))))
1689      ((eq match-form nil)
1690       nil)
1691      (t ;; Handle improper lists.  Last matching place, no need for shift
1692       (dash--match match-form (dash--match-cons-get-cdr skip-cdr source))))))
1693
1694 (defun dash--vector-tail (seq start)
1695   "Return the tail of SEQ starting at START."
1696   (cond
1697    ((vectorp seq)
1698     (let* ((re-length (- (length seq) start))
1699            (re (make-vector re-length 0)))
1700       (--dotimes re-length (aset re it (aref seq (+ it start))))
1701       re))
1702    ((stringp seq)
1703     (substring seq start))))
1704
1705 (defun dash--match-vector (match-form source)
1706   "Setup a vector matching environment and call the real matcher."
1707   (let ((s (dash--match-make-source-symbol)))
1708     (cond
1709      ;; don't bind `s' if we only have one sub-pattern
1710      ((= (length match-form) 1)
1711       (dash--match (aref match-form 0) `(aref ,source 0)))
1712      ;; if the source is a symbol, we don't need to re-bind it
1713      ((symbolp source)
1714       (dash--match-vector-1 match-form source))
1715      ;; don't bind `s' if we only have one sub-pattern which is not ignored
1716      ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form))
1717              (ignored-places-n (length (-remove 'null ignored-places))))
1718         (when (= ignored-places-n (1- (length match-form)))
1719           (let ((n (-find-index 'null ignored-places)))
1720             (dash--match (aref match-form n) `(aref ,source ,n))))))
1721      (t
1722       (cons (list s source) (dash--match-vector-1 match-form s))))))
1723
1724 (defun dash--match-vector-1 (match-form source)
1725   "Match MATCH-FORM against SOURCE.
1726
1727 MATCH-FORM is a vector.  Each element of MATCH-FORM is either a
1728 symbol, which gets bound to the respective value in source or
1729 another match form which gets destructured recursively.
1730
1731 If second-from-last place in MATCH-FORM is the symbol &rest, the
1732 next element of the MATCH-FORM is matched against the tail of
1733 SOURCE, starting at index of the &rest symbol.  This is
1734 conceptually the same as the (head . tail) match for improper
1735 lists, where dot plays the role of &rest.
1736
1737 SOURCE is a vector.
1738
1739 If the MATCH-FORM vector is shorter than SOURCE vector, only
1740 the (length MATCH-FORM) places are bound, the rest of the SOURCE
1741 is discarded."
1742   (let ((i 0)
1743         (l (length match-form))
1744         (re))
1745     (while (< i l)
1746       (let ((m (aref match-form i)))
1747         (push (cond
1748                ((and (symbolp m)
1749                      (eq m '&rest))
1750                 (prog1 (dash--match
1751                         (aref match-form (1+ i))
1752                         `(dash--vector-tail ,source ,i))
1753                   (setq i l)))
1754                ((and (symbolp m)
1755                      ;; do not match symbols starting with _
1756                      (not (eq (aref (symbol-name m) 0) ?_)))
1757                 (list (list m `(aref ,source ,i))))
1758                ((not (symbolp m))
1759                 (dash--match m `(aref ,source ,i))))
1760               re)
1761         (setq i (1+ i))))
1762     (-flatten-n 1 (nreverse re))))
1763
1764 (defun dash--match-kv-normalize-match-form (pattern)
1765   "Normalize kv PATTERN.
1766
1767 This method normalizes PATTERN to the format expected by
1768 `dash--match-kv'.  See `-let' for the specification."
1769   (let ((normalized (list (car pattern)))
1770         (skip nil)
1771         (fill-placeholder (make-symbol "--dash-fill-placeholder--")))
1772     (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern)))
1773       (lambda (pair)
1774         (let ((current (car pair))
1775               (next (cdr pair)))
1776           (if skip
1777               (setq skip nil)
1778             (if (or (eq fill-placeholder next)
1779                     (not (or (and (symbolp next)
1780                                   (not (keywordp next))
1781                                   (not (eq next t))
1782                                   (not (eq next nil)))
1783                              (and (consp next)
1784                                   (not (eq (car next) 'quote)))
1785                              (vectorp next))))
1786                 (progn
1787                   (cond
1788                    ((keywordp current)
1789                     (push current normalized)
1790                     (push (intern (substring (symbol-name current) 1)) normalized))
1791                    ((stringp current)
1792                     (push current normalized)
1793                     (push (intern current) normalized))
1794                    ((and (consp current)
1795                          (eq (car current) 'quote))
1796                     (push current normalized)
1797                     (push (cadr current) normalized))
1798                    (t (error "-let: found key `%s' in kv destructuring but its pattern `%s' is invalid and can not be derived from the key" current next)))
1799                   (setq skip nil))
1800               (push current normalized)
1801               (push next normalized)
1802               (setq skip t))))))
1803     (nreverse normalized)))
1804
1805 (defun dash--match-kv (match-form source)
1806   "Setup a kv matching environment and call the real matcher.
1807
1808 kv can be any key-value store, such as plist, alist or hash-table."
1809   (let ((s (dash--match-make-source-symbol)))
1810     (cond
1811      ;; don't bind `s' if we only have one sub-pattern (&type key val)
1812      ((= (length match-form) 3)
1813       (dash--match-kv-1 (cdr match-form) source (car match-form)))
1814      ;; if the source is a symbol, we don't need to re-bind it
1815      ((symbolp source)
1816       (dash--match-kv-1 (cdr match-form) source (car match-form)))
1817      (t
1818       (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form)))))))
1819
1820 (defun dash-expand:&hash (key source)
1821   "Generate extracting KEY from SOURCE for &hash destructuring."
1822   `(gethash ,key ,source))
1823
1824 (defun dash-expand:&plist (key source)
1825   "Generate extracting KEY from SOURCE for &plist destructuring."
1826   `(plist-get ,source ,key))
1827
1828 (defun dash-expand:&alist (key source)
1829   "Generate extracting KEY from SOURCE for &alist destructuring."
1830   `(cdr (assoc ,key ,source)))
1831
1832 (defun dash-expand:&hash? (key source)
1833   "Generate extracting KEY from SOURCE for &hash? destructuring.
1834 Similar to &hash but check whether the map is not nil."
1835   (let ((src (make-symbol "src")))
1836     `(let ((,src ,source))
1837        (when ,src (gethash ,key ,src)))))
1838
1839 (defalias 'dash-expand:&keys 'dash-expand:&plist)
1840
1841 (defun dash--match-kv-1 (match-form source type)
1842   "Match MATCH-FORM against SOURCE of type TYPE.
1843
1844 MATCH-FORM is a proper list of the form (key1 place1 ... keyN
1845 placeN).  Each placeK is either a symbol, which gets bound to the
1846 value of keyK retrieved from the key-value store, or another
1847 match form which gets destructured recursively.
1848
1849 SOURCE is a key-value store of type TYPE, which can be a plist,
1850 an alist or a hash table.
1851
1852 TYPE is a token specifying the type of the key-value store.
1853 Valid values are &plist, &alist and &hash."
1854   (-flatten-n 1 (-map
1855                  (lambda (kv)
1856                    (let* ((k (car kv))
1857                           (v (cadr kv))
1858                           (getter
1859                            (funcall (dash--get-expand-function type) k source)))
1860                      (cond
1861                       ((symbolp v)
1862                        (list (list v getter)))
1863                       (t (dash--match v getter)))))
1864                  (-partition 2 match-form))))
1865
1866 (defun dash--match-symbol (match-form source)
1867   "Bind a symbol.
1868
1869 This works just like `let', there is no destructuring."
1870   (list (list match-form source)))
1871
1872 (defun dash--match (match-form source)
1873   "Match MATCH-FORM against SOURCE.
1874
1875 This function tests the MATCH-FORM and dispatches to specific
1876 matchers based on the type of the expression.
1877
1878 Key-value stores are disambiguated by placing a token &plist,
1879 &alist or &hash as a first item in the MATCH-FORM."
1880   (cond
1881    ((symbolp match-form)
1882     (dash--match-symbol match-form source))
1883    ((consp match-form)
1884     (cond
1885      ;; Handle the "x &as" bindings first.
1886      ((and (consp (cdr match-form))
1887            (symbolp (car match-form))
1888            (eq '&as (cadr match-form)))
1889       (let ((s (car match-form)))
1890         (cons (list s source)
1891               (dash--match (cddr match-form) s))))
1892      ((functionp (dash--get-expand-function (car match-form)))
1893       (dash--match-kv (dash--match-kv-normalize-match-form match-form) source))
1894      (t (dash--match-cons match-form source))))
1895    ((vectorp match-form)
1896     ;; We support the &as binding in vectors too
1897     (cond
1898      ((and (> (length match-form) 2)
1899            (symbolp (aref match-form 0))
1900            (eq '&as (aref match-form 1)))
1901       (let ((s (aref match-form 0)))
1902         (cons (list s source)
1903               (dash--match (dash--vector-tail match-form 2) s))))
1904      (t (dash--match-vector match-form source))))))
1905
1906 (defun dash--normalize-let-varlist (varlist)
1907   "Normalize VARLIST so that every binding is a list.
1908
1909 `let' allows specifying a binding which is not a list but simply
1910 the place which is then automatically bound to nil, such that all
1911 three of the following are identical and evaluate to nil.
1912
1913   (let (a) a)
1914   (let ((a)) a)
1915   (let ((a nil)) a)
1916
1917 This function normalizes all of these to the last form."
1918   (--map (if (consp it) it (list it nil)) varlist))
1919
1920 (defmacro -let* (varlist &rest body)
1921   "Bind variables according to VARLIST then eval BODY.
1922
1923 VARLIST is a list of lists of the form (PATTERN SOURCE).  Each
1924 PATTERN is matched against the SOURCE structurally.  SOURCE is
1925 only evaluated once for each PATTERN.
1926
1927 Each SOURCE can refer to the symbols already bound by this
1928 VARLIST.  This is useful if you want to destructure SOURCE
1929 recursively but also want to name the intermediate structures.
1930
1931 See `-let' for the list of all possible patterns."
1932   (declare (debug ((&rest [&or (sexp form) sexp]) body))
1933            (indent 1))
1934   (let* ((varlist (dash--normalize-let-varlist varlist))
1935          (bindings (--mapcat (dash--match (car it) (cadr it)) varlist)))
1936     `(let* ,bindings
1937        ,@body)))
1938
1939 (defmacro -let (varlist &rest body)
1940   "Bind variables according to VARLIST then eval BODY.
1941
1942 VARLIST is a list of lists of the form (PATTERN SOURCE).  Each
1943 PATTERN is matched against the SOURCE \"structurally\".  SOURCE
1944 is only evaluated once for each PATTERN.  Each PATTERN is matched
1945 recursively, and can therefore contain sub-patterns which are
1946 matched against corresponding sub-expressions of SOURCE.
1947
1948 All the SOURCEs are evalled before any symbols are
1949 bound (i.e. \"in parallel\").
1950
1951 If VARLIST only contains one (PATTERN SOURCE) element, you can
1952 optionally specify it using a vector and discarding the
1953 outer-most parens.  Thus
1954
1955   (-let ((PATTERN SOURCE)) ..)
1956
1957 becomes
1958
1959   (-let [PATTERN SOURCE] ..).
1960
1961 `-let' uses a convention of not binding places (symbols) starting
1962 with _ whenever it's possible.  You can use this to skip over
1963 entries you don't care about.  However, this is not *always*
1964 possible (as a result of implementation) and these symbols might
1965 get bound to undefined values.
1966
1967 Following is the overview of supported patterns.  Remember that
1968 patterns can be matched recursively, so every a, b, aK in the
1969 following can be a matching construct and not necessarily a
1970 symbol/variable.
1971
1972 Symbol:
1973
1974   a - bind the SOURCE to A.  This is just like regular `let'.
1975
1976 Conses and lists:
1977
1978   (a) - bind `car' of cons/list to A
1979
1980   (a . b) - bind car of cons to A and `cdr' to B
1981
1982   (a b) - bind car of list to A and `cadr' to B
1983
1984   (a1 a2 a3  ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ...
1985
1986   (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST.
1987
1988 Vectors:
1989
1990   [a] - bind 0th element of a non-list sequence to A (works with
1991         vectors, strings, bit arrays...)
1992
1993   [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to
1994                    A1, 2nd to A2, ...
1995                    If the PATTERN is shorter than SOURCE, the values at
1996                    places not in PATTERN are ignored.
1997                    If the PATTERN is longer than SOURCE, an `error' is
1998                    thrown.
1999
2000   [a1 a2 a3 ... &rest rest] - as above, but bind the rest of
2001                               the sequence to REST.  This is
2002                               conceptually the same as improper list
2003                               matching (a1 a2 ... aN . rest)
2004
2005 Key/value stores:
2006
2007   (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
2008                                  SOURCE plist to aK.  If the
2009                                  value is not found, aK is nil.
2010                                  Uses `plist-get' to fetch values.
2011
2012   (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
2013                                  SOURCE alist to aK.  If the
2014                                  value is not found, aK is nil.
2015                                  Uses `assoc' to fetch values.
2016
2017   (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
2018                                 SOURCE hash table to aK.  If the
2019                                 value is not found, aK is nil.
2020                                 Uses `gethash' to fetch values.
2021
2022 Further, special keyword &keys supports \"inline\" matching of
2023 plist-like key-value pairs, similarly to &keys keyword of
2024 `cl-defun'.
2025
2026   (a1 a2 ... aN &keys key1 b1 ... keyN bK)
2027
2028 This binds N values from the list to a1 ... aN, then interprets
2029 the cdr as a plist (see key/value matching above).
2030
2031 A shorthand notation for kv-destructuring exists which allows the
2032 patterns be optionally left out and derived from the key name in
2033 the following fashion:
2034
2035 - a key :foo is converted into `foo' pattern,
2036 - a key 'bar is converted into `bar' pattern,
2037 - a key \"baz\" is converted into `baz' pattern.
2038
2039 That is, the entire value under the key is bound to the derived
2040 variable without any further destructuring.
2041
2042 This is possible only when the form following the key is not a
2043 valid pattern (i.e. not a symbol, a cons cell or a vector).
2044 Otherwise the matching proceeds as usual and in case of an
2045 invalid spec fails with an error.
2046
2047 Thus the patterns are normalized as follows:
2048
2049    ;; derive all the missing patterns
2050    (&plist :foo 'bar \"baz\") => (&plist :foo foo 'bar bar \"baz\" baz)
2051
2052    ;; we can specify some but not others
2053    (&plist :foo 'bar explicit-bar) => (&plist :foo foo 'bar explicit-bar)
2054
2055    ;; nothing happens, we store :foo in x
2056    (&plist :foo x) => (&plist :foo x)
2057
2058    ;; nothing happens, we match recursively
2059    (&plist :foo (a b c)) => (&plist :foo (a b c))
2060
2061 You can name the source using the syntax SYMBOL &as PATTERN.
2062 This syntax works with lists (proper or improper), vectors and
2063 all types of maps.
2064
2065   (list &as a b c) (list 1 2 3)
2066
2067 binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
2068
2069 Similarly:
2070
2071   (bounds &as beg . end) (cons 1 2)
2072
2073 binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
2074
2075   (items &as first . rest) (list 1 2 3)
2076
2077 binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
2078
2079   [vect &as _ b c] [1 2 3]
2080
2081 binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual).
2082
2083   (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
2084
2085 binds B to 2 and PLIST to (:a 1 :b 2 :c 3).  Same for &alist and &hash.
2086
2087 This is especially useful when we want to capture the result of a
2088 computation and destructure at the same time.  Consider the
2089 form (function-returning-complex-structure) returning a list of
2090 two vectors with two items each.  We want to capture this entire
2091 result and pass it to another computation, but at the same time
2092 we want to get the second item from each vector.  We can achieve
2093 it with pattern
2094
2095   (result &as [_ a] [_ b]) (function-returning-complex-structure)
2096
2097 Note: Clojure programmers may know this feature as the \":as
2098 binding\".  The difference is that we put the &as at the front
2099 because we need to support improper list binding."
2100   (declare (debug ([&or (&rest [&or (sexp form) sexp])
2101                         (vector [&rest [sexp form]])]
2102                    body))
2103            (indent 1))
2104   (if (vectorp varlist)
2105       `(let* ,(dash--match (aref varlist 0) (aref varlist 1))
2106          ,@body)
2107     (let* ((varlist (dash--normalize-let-varlist varlist))
2108            (inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist))
2109            (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs))))
2110       `(let ,inputs
2111          (-let* ,new-varlist ,@body)))))
2112
2113 (defmacro -lambda (match-form &rest body)
2114   "Return a lambda which destructures its input as MATCH-FORM and executes BODY.
2115
2116 Note that you have to enclose the MATCH-FORM in a pair of parens,
2117 such that:
2118
2119   (-lambda (x) body)
2120   (-lambda (x y ...) body)
2121
2122 has the usual semantics of `lambda'.  Furthermore, these get
2123 translated into normal lambda, so there is no performance
2124 penalty.
2125
2126 See `-let' for the description of destructuring mechanism."
2127   (declare (doc-string 2) (indent defun)
2128            (debug (&define sexp
2129                            [&optional stringp]
2130                            [&optional ("interactive" interactive)]
2131                            def-body)))
2132   (cond
2133    ((not (consp match-form))
2134     (signal 'wrong-type-argument "match-form must be a list"))
2135    ;; no destructuring, so just return regular lambda to make things faster
2136    ((-all? 'symbolp match-form)
2137     `(lambda ,match-form ,@body))
2138    (t
2139     (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form)))
2140       ;; TODO: because inputs to the lambda are evaluated only once,
2141       ;; -let* need not to create the extra bindings to ensure that.
2142       ;; We should find a way to optimize that.  Not critical however.
2143       `(lambda ,(--map (cadr it) inputs)
2144          (-let* ,inputs ,@body))))))
2145
2146 (defmacro -setq (&rest forms)
2147   "Bind each MATCH-FORM to the value of its VAL.
2148
2149 MATCH-FORM destructuring is done according to the rules of `-let'.
2150
2151 This macro allows you to bind multiple variables by destructuring
2152 the value, so for example:
2153
2154   (-setq (a b) x
2155          (&plist :c c) plist)
2156
2157 expands roughly speaking to the following code
2158
2159   (setq a (car x)
2160         b (cadr x)
2161         c (plist-get plist :c))
2162
2163 Care is taken to only evaluate each VAL once so that in case of
2164 multiple assignments it does not cause unexpected side effects.
2165
2166 \(fn [MATCH-FORM VAL]...)"
2167   (declare (debug (&rest sexp form))
2168            (indent 1))
2169   (when (= (mod (length forms) 2) 1)
2170     (error "Odd number of arguments"))
2171   (let* ((forms-and-sources
2172           ;; First get all the necessary mappings with all the
2173           ;; intermediate bindings.
2174           (-map (lambda (x) (dash--match (car x) (cadr x)))
2175                 (-partition 2 forms)))
2176          ;; To preserve the logic of dynamic scoping we must ensure
2177          ;; that we `setq' the variables outside of the `let*' form
2178          ;; which holds the destructured intermediate values.  For
2179          ;; this we generate for each variable a placeholder which is
2180          ;; bound to (lexically) the result of the destructuring.
2181          ;; Then outside of the helper `let*' form we bind all the
2182          ;; original variables to their respective placeholders.
2183          ;; TODO: There is a lot of room for possible optimization,
2184          ;; for start playing with `special-variable-p' to eliminate
2185          ;; unnecessary re-binding.
2186          (variables-to-placeholders
2187           (-mapcat
2188            (lambda (bindings)
2189              (-map
2190               (lambda (binding)
2191                 (let ((var (car binding)))
2192                   (list var (make-symbol (concat "--dash-binding-" (symbol-name var) "--")))))
2193               (--filter (not (string-prefix-p "--" (symbol-name (car it)))) bindings)))
2194            forms-and-sources)))
2195     `(let ,(-map 'cadr variables-to-placeholders)
2196        (let* ,(-flatten-n 1 forms-and-sources)
2197          (setq ,@(-flatten (-map 'reverse variables-to-placeholders))))
2198        (setq ,@(-flatten variables-to-placeholders)))))
2199
2200 (defmacro -if-let* (vars-vals then &rest else)
2201   "If all VALS evaluate to true, bind them to their corresponding
2202 VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list
2203 of (VAR VAL) pairs.
2204
2205 Note: binding is done according to `-let*'.  VALS are evaluated
2206 sequentially, and evaluation stops after the first nil VAL is
2207 encountered."
2208   (declare (debug ((&rest (sexp form)) form body))
2209            (indent 2))
2210   (->> vars-vals
2211        (--mapcat (dash--match (car it) (cadr it)))
2212        (--reduce-r-from
2213         (let ((var (car it))
2214               (val (cadr it)))
2215           `(let ((,var ,val))
2216              (if ,var ,acc ,@else)))
2217         then)))
2218
2219 (defmacro -if-let (var-val then &rest else)
2220   "If VAL evaluates to non-nil, bind it to VAR and do THEN,
2221 otherwise do ELSE.
2222
2223 Note: binding is done according to `-let'.
2224
2225 \(fn (VAR VAL) THEN &rest ELSE)"
2226   (declare (debug ((sexp form) form body))
2227            (indent 2))
2228   `(-if-let* (,var-val) ,then ,@else))
2229
2230 (defmacro --if-let (val then &rest else)
2231   "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN,
2232 otherwise do ELSE."
2233   (declare (debug (form form body))
2234            (indent 2))
2235   `(-if-let (it ,val) ,then ,@else))
2236
2237 (defmacro -when-let* (vars-vals &rest body)
2238   "If all VALS evaluate to true, bind them to their corresponding
2239 VARS and execute body. VARS-VALS should be a list of (VAR VAL)
2240 pairs.
2241
2242 Note: binding is done according to `-let*'.  VALS are evaluated
2243 sequentially, and evaluation stops after the first nil VAL is
2244 encountered."
2245   (declare (debug ((&rest (sexp form)) body))
2246            (indent 1))
2247   `(-if-let* ,vars-vals (progn ,@body)))
2248
2249 (defmacro -when-let (var-val &rest body)
2250   "If VAL evaluates to non-nil, bind it to VAR and execute body.
2251
2252 Note: binding is done according to `-let'.
2253
2254 \(fn (VAR VAL) &rest BODY)"
2255   (declare (debug ((sexp form) body))
2256            (indent 1))
2257   `(-if-let ,var-val (progn ,@body)))
2258
2259 (defmacro --when-let (val &rest body)
2260   "If VAL evaluates to non-nil, bind it to symbol `it' and
2261 execute body."
2262   (declare (debug (form body))
2263            (indent 1))
2264   `(--if-let ,val (progn ,@body)))
2265
2266 (defvar -compare-fn nil
2267   "Tests for equality use this function or `equal' if this is nil.
2268 It should only be set using dynamic scope with a let, like:
2269
2270   (let ((-compare-fn #\\='=)) (-union numbers1 numbers2 numbers3)")
2271
2272 (defun -distinct (list)
2273   "Return a new list with all duplicates removed.
2274 The test for equality is done with `equal',
2275 or with `-compare-fn' if that's non-nil.
2276
2277 Alias: `-uniq'"
2278   (let (result)
2279     (--each list (unless (-contains? result it) (!cons it result)))
2280     (nreverse result)))
2281
2282 (defalias '-uniq '-distinct)
2283
2284 (defun -union (list list2)
2285   "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST.
2286 The test for equality is done with `equal',
2287 or with `-compare-fn' if that's non-nil."
2288   ;; We fall back to iteration implementation if the comparison
2289   ;; function isn't one of `eq', `eql' or `equal'.
2290   (let* ((result (reverse list))
2291          ;; TODO: get rid of this dynamic variable, pass it as an
2292          ;; argument instead.
2293          (-compare-fn (if (bound-and-true-p -compare-fn)
2294                           -compare-fn
2295                         'equal)))
2296     (if (memq -compare-fn '(eq eql equal))
2297         (let ((ht (make-hash-table :test -compare-fn)))
2298           (--each list (puthash it t ht))
2299           (--each list2 (unless (gethash it ht) (!cons it result))))
2300       (--each list2 (unless (-contains? result it) (!cons it result))))
2301     (nreverse result)))
2302
2303 (defun -intersection (list list2)
2304   "Return a new list containing only the elements that are members of both LIST and LIST2.
2305 The test for equality is done with `equal',
2306 or with `-compare-fn' if that's non-nil."
2307   (--filter (-contains? list2 it) list))
2308
2309 (defun -difference (list list2)
2310   "Return a new list with only the members of LIST that are not in LIST2.
2311 The test for equality is done with `equal',
2312 or with `-compare-fn' if that's non-nil."
2313   (--filter (not (-contains? list2 it)) list))
2314
2315 (defun -powerset (list)
2316   "Return the power set of LIST."
2317   (if (null list) '(())
2318     (let ((last (-powerset (cdr list))))
2319       (append (mapcar (lambda (x) (cons (car list) x)) last)
2320               last))))
2321
2322 (defun -permutations (list)
2323   "Return the permutations of LIST."
2324   (if (null list) '(())
2325     (apply #'append
2326            (mapcar (lambda (x)
2327                      (mapcar (lambda (perm) (cons x perm))
2328                              (-permutations (remove x list))))
2329                    list))))
2330
2331 (defun -inits (list)
2332   "Return all prefixes of LIST."
2333   (nreverse (-map 'reverse (-tails (nreverse list)))))
2334
2335 (defun -tails (list)
2336   "Return all suffixes of LIST"
2337   (-reductions-r-from 'cons nil list))
2338
2339 (defun -common-prefix (&rest lists)
2340   "Return the longest common prefix of LISTS."
2341   (declare (pure t) (side-effect-free t))
2342   (--reduce (--take-while (and acc (equal (pop acc) it)) it)
2343             lists))
2344
2345 (defun -common-suffix (&rest lists)
2346   "Return the longest common suffix of LISTS."
2347   (nreverse (apply #'-common-prefix (mapcar #'reverse lists))))
2348
2349 (defun -contains? (list element)
2350   "Return non-nil if LIST contains ELEMENT.
2351
2352 The test for equality is done with `equal', or with `-compare-fn'
2353 if that's non-nil.
2354
2355 Alias: `-contains-p'"
2356   (not
2357    (null
2358     (cond
2359      ((null -compare-fn)    (member element list))
2360      ((eq -compare-fn 'eq)  (memq element list))
2361      ((eq -compare-fn 'eql) (memql element list))
2362      (t
2363       (let ((lst list))
2364         (while (and lst
2365                     (not (funcall -compare-fn element (car lst))))
2366           (setq lst (cdr lst)))
2367         lst))))))
2368
2369 (defalias '-contains-p '-contains?)
2370
2371 (defun -same-items? (list list2)
2372   "Return true if LIST and LIST2 has the same items.
2373
2374 The order of the elements in the lists does not matter.
2375
2376 Alias: `-same-items-p'"
2377   (let ((length-a (length list))
2378         (length-b (length list2)))
2379     (and
2380      (= length-a length-b)
2381      (= length-a (length (-intersection list list2))))))
2382
2383 (defalias '-same-items-p '-same-items?)
2384
2385 (defun -is-prefix? (prefix list)
2386   "Return non-nil if PREFIX is prefix of LIST.
2387
2388 Alias: `-is-prefix-p'"
2389   (declare (pure t) (side-effect-free t))
2390   (--each-while list (equal (car prefix) it)
2391     (!cdr prefix))
2392   (not prefix))
2393
2394 (defun -is-suffix? (suffix list)
2395   "Return non-nil if SUFFIX is suffix of LIST.
2396
2397 Alias: `-is-suffix-p'"
2398   (declare (pure t) (side-effect-free t))
2399   (-is-prefix? (reverse suffix) (reverse list)))
2400
2401 (defun -is-infix? (infix list)
2402   "Return non-nil if INFIX is infix of LIST.
2403
2404 This operation runs in O(n^2) time
2405
2406 Alias: `-is-infix-p'"
2407   (declare (pure t) (side-effect-free t))
2408   (let (done)
2409     (while (and (not done) list)
2410       (setq done (-is-prefix? infix list))
2411       (!cdr list))
2412     done))
2413
2414 (defalias '-is-prefix-p '-is-prefix?)
2415 (defalias '-is-suffix-p '-is-suffix?)
2416 (defalias '-is-infix-p '-is-infix?)
2417
2418 (defun -sort (comparator list)
2419   "Sort LIST, stably, comparing elements using COMPARATOR.
2420 Return the sorted list.  LIST is NOT modified by side effects.
2421 COMPARATOR is called with two elements of LIST, and should return non-nil
2422 if the first element should sort before the second."
2423   (sort (copy-sequence list) comparator))
2424
2425 (defmacro --sort (form list)
2426   "Anaphoric form of `-sort'."
2427   (declare (debug (form form)))
2428   `(-sort (lambda (it other) ,form) ,list))
2429
2430 (defun -list (&rest args)
2431   "Return a list with ARGS.
2432
2433 If first item of ARGS is already a list, simply return ARGS.  If
2434 not, return a list with ARGS as elements."
2435   (declare (pure t) (side-effect-free t))
2436   (let ((arg (car args)))
2437     (if (listp arg) arg args)))
2438
2439 (defun -repeat (n x)
2440   "Return a list with X repeated N times.
2441 Return nil if N is less than 1."
2442   (declare (pure t) (side-effect-free t))
2443   (let (ret)
2444     (--dotimes n (!cons x ret))
2445     ret))
2446
2447 (defun -sum (list)
2448   "Return the sum of LIST."
2449   (declare (pure t) (side-effect-free t))
2450   (apply '+ list))
2451
2452 (defun -running-sum (list)
2453   "Return a list with running sums of items in LIST.
2454
2455 LIST must be non-empty."
2456   (declare (pure t) (side-effect-free t))
2457   (unless (consp list)
2458     (error "LIST must be non-empty"))
2459   (-reductions '+ list))
2460
2461 (defun -product (list)
2462   "Return the product of LIST."
2463   (declare (pure t) (side-effect-free t))
2464   (apply '* list))
2465
2466 (defun -running-product (list)
2467   "Return a list with running products of items in LIST.
2468
2469 LIST must be non-empty."
2470   (declare (pure t) (side-effect-free t))
2471   (unless (consp list)
2472     (error "LIST must be non-empty"))
2473   (-reductions '* list))
2474
2475 (defun -max (list)
2476   "Return the largest value from LIST of numbers or markers."
2477   (declare (pure t) (side-effect-free t))
2478   (apply 'max list))
2479
2480 (defun -min (list)
2481   "Return the smallest value from LIST of numbers or markers."
2482   (declare (pure t) (side-effect-free t))
2483   (apply 'min list))
2484
2485 (defun -max-by (comparator list)
2486   "Take a comparison function COMPARATOR and a LIST and return
2487 the greatest element of the list by the comparison function.
2488
2489 See also combinator `-on' which can transform the values before
2490 comparing them."
2491   (--reduce (if (funcall comparator it acc) it acc) list))
2492
2493 (defun -min-by (comparator list)
2494   "Take a comparison function COMPARATOR and a LIST and return
2495 the least element of the list by the comparison function.
2496
2497 See also combinator `-on' which can transform the values before
2498 comparing them."
2499   (--reduce (if (funcall comparator it acc) acc it) list))
2500
2501 (defmacro --max-by (form list)
2502   "Anaphoric version of `-max-by'.
2503
2504 The items for the comparator form are exposed as \"it\" and \"other\"."
2505   (declare (debug (form form)))
2506   `(-max-by (lambda (it other) ,form) ,list))
2507
2508 (defmacro --min-by (form list)
2509   "Anaphoric version of `-min-by'.
2510
2511 The items for the comparator form are exposed as \"it\" and \"other\"."
2512   (declare (debug (form form)))
2513   `(-min-by (lambda (it other) ,form) ,list))
2514
2515 (defun -iterate (fun init n)
2516   "Return a list of iterated applications of FUN to INIT.
2517
2518 This means a list of form:
2519
2520   (init (fun init) (fun (fun init)) ...)
2521
2522 N is the length of the returned list."
2523   (if (= n 0) nil
2524     (let ((r (list init)))
2525       (--dotimes (1- n)
2526         (push (funcall fun (car r)) r))
2527       (nreverse r))))
2528
2529 (defun -fix (fn list)
2530   "Compute the (least) fixpoint of FN with initial input LIST.
2531
2532 FN is called at least once, results are compared with `equal'."
2533   (let ((re (funcall fn list)))
2534     (while (not (equal list re))
2535       (setq list re)
2536       (setq re (funcall fn re)))
2537     re))
2538
2539 (defmacro --fix (form list)
2540   "Anaphoric form of `-fix'."
2541   `(-fix (lambda (it) ,form) ,list))
2542
2543 (defun -unfold (fun seed)
2544   "Build a list from SEED using FUN.
2545
2546 This is \"dual\" operation to `-reduce-r': while -reduce-r
2547 consumes a list to produce a single value, `-unfold' takes a
2548 seed value and builds a (potentially infinite!) list.
2549
2550 FUN should return `nil' to stop the generating process, or a
2551 cons (A . B), where A will be prepended to the result and B is
2552 the new seed."
2553   (let ((last (funcall fun seed)) r)
2554     (while last
2555       (push (car last) r)
2556       (setq last (funcall fun (cdr last))))
2557     (nreverse r)))
2558
2559 (defmacro --unfold (form seed)
2560   "Anaphoric version of `-unfold'."
2561   (declare (debug (form form)))
2562   `(-unfold (lambda (it) ,form) ,seed))
2563
2564 (defun -cons-pair? (con)
2565   "Return non-nil if CON is true cons pair.
2566 That is (A . B) where B is not a list.
2567
2568 Alias: `-cons-pair-p'"
2569   (declare (pure t) (side-effect-free t))
2570   (and (listp con)
2571        (not (listp (cdr con)))))
2572
2573 (defalias '-cons-pair-p '-cons-pair?)
2574
2575 (defun -cons-to-list (con)
2576   "Convert a cons pair to a list with `car' and `cdr' of the pair respectively."
2577   (declare (pure t) (side-effect-free t))
2578   (list (car con) (cdr con)))
2579
2580 (defun -value-to-list (val)
2581   "Convert a value to a list.
2582
2583 If the value is a cons pair, make a list with two elements, `car'
2584 and `cdr' of the pair respectively.
2585
2586 If the value is anything else, wrap it in a list."
2587   (declare (pure t) (side-effect-free t))
2588   (cond
2589    ((-cons-pair? val) (-cons-to-list val))
2590    (t (list val))))
2591
2592 (defun -tree-mapreduce-from (fn folder init-value tree)
2593   "Apply FN to each element of TREE, and make a list of the results.
2594 If elements of TREE are lists themselves, apply FN recursively to
2595 elements of these nested lists.
2596
2597 Then reduce the resulting lists using FOLDER and initial value
2598 INIT-VALUE. See `-reduce-r-from'.
2599
2600 This is the same as calling `-tree-reduce-from' after `-tree-map'
2601 but is twice as fast as it only traverse the structure once."
2602   (cond
2603    ((not tree) nil)
2604    ((-cons-pair? tree) (funcall fn tree))
2605    ((listp tree)
2606     (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree)))
2607    (t (funcall fn tree))))
2608
2609 (defmacro --tree-mapreduce-from (form folder init-value tree)
2610   "Anaphoric form of `-tree-mapreduce-from'."
2611   (declare (debug (form form form form)))
2612   `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree))
2613
2614 (defun -tree-mapreduce (fn folder tree)
2615   "Apply FN to each element of TREE, and make a list of the results.
2616 If elements of TREE are lists themselves, apply FN recursively to
2617 elements of these nested lists.
2618
2619 Then reduce the resulting lists using FOLDER and initial value
2620 INIT-VALUE. See `-reduce-r-from'.
2621
2622 This is the same as calling `-tree-reduce' after `-tree-map'
2623 but is twice as fast as it only traverse the structure once."
2624   (cond
2625    ((not tree) nil)
2626    ((-cons-pair? tree) (funcall fn tree))
2627    ((listp tree)
2628     (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree)))
2629    (t (funcall fn tree))))
2630
2631 (defmacro --tree-mapreduce (form folder tree)
2632   "Anaphoric form of `-tree-mapreduce'."
2633   (declare (debug (form form form)))
2634   `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree))
2635
2636 (defun -tree-map (fn tree)
2637   "Apply FN to each element of TREE while preserving the tree structure."
2638   (cond
2639    ((not tree) nil)
2640    ((-cons-pair? tree) (funcall fn tree))
2641    ((listp tree)
2642     (mapcar (lambda (x) (-tree-map fn x)) tree))
2643    (t (funcall fn tree))))
2644
2645 (defmacro --tree-map (form tree)
2646   "Anaphoric form of `-tree-map'."
2647   (declare (debug (form form)))
2648   `(-tree-map (lambda (it) ,form) ,tree))
2649
2650 (defun -tree-reduce-from (fn init-value tree)
2651   "Use FN to reduce elements of list TREE.
2652 If elements of TREE are lists themselves, apply the reduction recursively.
2653
2654 FN is first applied to INIT-VALUE and first element of the list,
2655 then on this result and second element from the list etc.
2656
2657 The initial value is ignored on cons pairs as they always contain
2658 two elements."
2659   (cond
2660    ((not tree) nil)
2661    ((-cons-pair? tree) tree)
2662    ((listp tree)
2663     (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree)))
2664    (t tree)))
2665
2666 (defmacro --tree-reduce-from (form init-value tree)
2667   "Anaphoric form of `-tree-reduce-from'."
2668   (declare (debug (form form form)))
2669   `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree))
2670
2671 (defun -tree-reduce (fn tree)
2672   "Use FN to reduce elements of list TREE.
2673 If elements of TREE are lists themselves, apply the reduction recursively.
2674
2675 FN is first applied to first element of the list and second
2676 element, then on this result and third element from the list etc.
2677
2678 See `-reduce-r' for how exactly are lists of zero or one element handled."
2679   (cond
2680    ((not tree) nil)
2681    ((-cons-pair? tree) tree)
2682    ((listp tree)
2683     (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree)))
2684    (t tree)))
2685
2686 (defmacro --tree-reduce (form tree)
2687   "Anaphoric form of `-tree-reduce'."
2688   (declare (debug (form form)))
2689   `(-tree-reduce (lambda (it acc) ,form) ,tree))
2690
2691 (defun -tree-map-nodes (pred fun tree)
2692   "Call FUN on each node of TREE that satisfies PRED.
2693
2694 If PRED returns nil, continue descending down this node.  If PRED
2695 returns non-nil, apply FUN to this node and do not descend
2696 further."
2697   (if (funcall pred tree)
2698       (funcall fun tree)
2699     (if (and (listp tree)
2700              (not (-cons-pair? tree)))
2701         (-map (lambda (x) (-tree-map-nodes pred fun x)) tree)
2702       tree)))
2703
2704 (defmacro --tree-map-nodes (pred form tree)
2705   "Anaphoric form of `-tree-map-nodes'."
2706   `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree))
2707
2708 (defun -tree-seq (branch children tree)
2709   "Return a sequence of the nodes in TREE, in depth-first search order.
2710
2711 BRANCH is a predicate of one argument that returns non-nil if the
2712 passed argument is a branch, that is, a node that can have children.
2713
2714 CHILDREN is a function of one argument that returns the children
2715 of the passed branch node.
2716
2717 Non-branch nodes are simply copied."
2718   (cons tree
2719         (when (funcall branch tree)
2720           (-mapcat (lambda (x) (-tree-seq branch children x))
2721                    (funcall children tree)))))
2722
2723 (defmacro --tree-seq (branch children tree)
2724   "Anaphoric form of `-tree-seq'."
2725   `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree))
2726
2727 (defun -clone (list)
2728   "Create a deep copy of LIST.
2729 The new list has the same elements and structure but all cons are
2730 replaced with new ones.  This is useful when you need to clone a
2731 structure such as plist or alist."
2732   (declare (pure t) (side-effect-free t))
2733   (-tree-map 'identity list))
2734
2735 (defun dash-enable-font-lock ()
2736   "Add syntax highlighting to dash functions, macros and magic values."
2737   (eval-after-load 'lisp-mode
2738     '(progn
2739        (let ((new-keywords '(
2740                              "!cons"
2741                              "!cdr"
2742                              "-each"
2743                              "--each"
2744                              "-each-indexed"
2745                              "--each-indexed"
2746                              "-each-while"
2747                              "--each-while"
2748                              "-doto"
2749                              "-dotimes"
2750                              "--dotimes"
2751                              "-map"
2752                              "--map"
2753                              "-reduce-from"
2754                              "--reduce-from"
2755                              "-reduce"
2756                              "--reduce"
2757                              "-reduce-r-from"
2758                              "--reduce-r-from"
2759                              "-reduce-r"
2760                              "--reduce-r"
2761                              "-reductions-from"
2762                              "-reductions-r-from"
2763                              "-reductions"
2764                              "-reductions-r"
2765                              "-filter"
2766                              "--filter"
2767                              "-select"
2768                              "--select"
2769                              "-remove"
2770                              "--remove"
2771                              "-reject"
2772                              "--reject"
2773                              "-remove-first"
2774                              "--remove-first"
2775                              "-reject-first"
2776                              "--reject-first"
2777                              "-remove-last"
2778                              "--remove-last"
2779                              "-reject-last"
2780                              "--reject-last"
2781                              "-remove-item"
2782                              "-non-nil"
2783                              "-keep"
2784                              "--keep"
2785                              "-map-indexed"
2786                              "--map-indexed"
2787                              "-splice"
2788                              "--splice"
2789                              "-splice-list"
2790                              "--splice-list"
2791                              "-map-when"
2792                              "--map-when"
2793                              "-replace-where"
2794                              "--replace-where"
2795                              "-map-first"
2796                              "--map-first"
2797                              "-map-last"
2798                              "--map-last"
2799                              "-replace"
2800                              "-replace-first"
2801                              "-replace-last"
2802                              "-flatten"
2803                              "-flatten-n"
2804                              "-concat"
2805                              "-mapcat"
2806                              "--mapcat"
2807                              "-copy"
2808                              "-cons*"
2809                              "-snoc"
2810                              "-first"
2811                              "--first"
2812                              "-find"
2813                              "--find"
2814                              "-some"
2815                              "--some"
2816                              "-any"
2817                              "--any"
2818                              "-last"
2819                              "--last"
2820                              "-first-item"
2821                              "-second-item"
2822                              "-third-item"
2823                              "-fourth-item"
2824                              "-fifth-item"
2825                              "-last-item"
2826                              "-butlast"
2827                              "-count"
2828                              "--count"
2829                              "-any?"
2830                              "--any?"
2831                              "-some?"
2832                              "--some?"
2833                              "-any-p"
2834                              "--any-p"
2835                              "-some-p"
2836                              "--some-p"
2837                              "-some->"
2838                              "-some->>"
2839                              "-some-->"
2840                              "-all?"
2841                              "-all-p"
2842                              "--all?"
2843                              "--all-p"
2844                              "-every?"
2845                              "--every?"
2846                              "-all-p"
2847                              "--all-p"
2848                              "-every-p"
2849                              "--every-p"
2850                              "-none?"
2851                              "--none?"
2852                              "-none-p"
2853                              "--none-p"
2854                              "-only-some?"
2855                              "--only-some?"
2856                              "-only-some-p"
2857                              "--only-some-p"
2858                              "-slice"
2859                              "-take"
2860                              "-drop"
2861                              "-drop-last"
2862                              "-take-last"
2863                              "-take-while"
2864                              "--take-while"
2865                              "-drop-while"
2866                              "--drop-while"
2867                              "-split-at"
2868                              "-rotate"
2869                              "-insert-at"
2870                              "-replace-at"
2871                              "-update-at"
2872                              "--update-at"
2873                              "-remove-at"
2874                              "-remove-at-indices"
2875                              "-split-with"
2876                              "--split-with"
2877                              "-split-on"
2878                              "-split-when"
2879                              "--split-when"
2880                              "-separate"
2881                              "--separate"
2882                              "-partition-all-in-steps"
2883                              "-partition-in-steps"
2884                              "-partition-all"
2885                              "-partition"
2886                              "-partition-after-item"
2887                              "-partition-after-pred"
2888                              "-partition-before-item"
2889                              "-partition-before-pred"
2890                              "-partition-by"
2891                              "--partition-by"
2892                              "-partition-by-header"
2893                              "--partition-by-header"
2894                              "-group-by"
2895                              "--group-by"
2896                              "-interpose"
2897                              "-interleave"
2898                              "-unzip"
2899                              "-zip-with"
2900                              "--zip-with"
2901                              "-zip"
2902                              "-zip-fill"
2903                              "-zip-pair"
2904                              "-cycle"
2905                              "-pad"
2906                              "-annotate"
2907                              "--annotate"
2908                              "-table"
2909                              "-table-flat"
2910                              "-partial"
2911                              "-elem-index"
2912                              "-elem-indices"
2913                              "-find-indices"
2914                              "--find-indices"
2915                              "-find-index"
2916                              "--find-index"
2917                              "-find-last-index"
2918                              "--find-last-index"
2919                              "-select-by-indices"
2920                              "-select-columns"
2921                              "-select-column"
2922                              "-grade-up"
2923                              "-grade-down"
2924                              "->"
2925                              "->>"
2926                              "-->"
2927                              "-as->"
2928                              "-when-let"
2929                              "-when-let*"
2930                              "--when-let"
2931                              "-if-let"
2932                              "-if-let*"
2933                              "--if-let"
2934                              "-let*"
2935                              "-let"
2936                              "-lambda"
2937                              "-distinct"
2938                              "-uniq"
2939                              "-union"
2940                              "-intersection"
2941                              "-difference"
2942                              "-powerset"
2943                              "-permutations"
2944                              "-inits"
2945                              "-tails"
2946                              "-common-prefix"
2947                              "-common-suffix"
2948                              "-contains?"
2949                              "-contains-p"
2950                              "-same-items?"
2951                              "-same-items-p"
2952                              "-is-prefix-p"
2953                              "-is-prefix?"
2954                              "-is-suffix-p"
2955                              "-is-suffix?"
2956                              "-is-infix-p"
2957                              "-is-infix?"
2958                              "-sort"
2959                              "--sort"
2960                              "-list"
2961                              "-repeat"
2962                              "-sum"
2963                              "-running-sum"
2964                              "-product"
2965                              "-running-product"
2966                              "-max"
2967                              "-min"
2968                              "-max-by"
2969                              "--max-by"
2970                              "-min-by"
2971                              "--min-by"
2972                              "-iterate"
2973                              "--iterate"
2974                              "-fix"
2975                              "--fix"
2976                              "-unfold"
2977                              "--unfold"
2978                              "-cons-pair?"
2979                              "-cons-pair-p"
2980                              "-cons-to-list"
2981                              "-value-to-list"
2982                              "-tree-mapreduce-from"
2983                              "--tree-mapreduce-from"
2984                              "-tree-mapreduce"
2985                              "--tree-mapreduce"
2986                              "-tree-map"
2987                              "--tree-map"
2988                              "-tree-reduce-from"
2989                              "--tree-reduce-from"
2990                              "-tree-reduce"
2991                              "--tree-reduce"
2992                              "-tree-seq"
2993                              "--tree-seq"
2994                              "-tree-map-nodes"
2995                              "--tree-map-nodes"
2996                              "-clone"
2997                              "-rpartial"
2998                              "-juxt"
2999                              "-applify"
3000                              "-on"
3001                              "-flip"
3002                              "-const"
3003                              "-cut"
3004                              "-orfn"
3005                              "-andfn"
3006                              "-iteratefn"
3007                              "-fixfn"
3008                              "-prodfn"
3009                              ))
3010              (special-variables '(
3011                                   "it"
3012                                   "it-index"
3013                                   "acc"
3014                                   "other"
3015                                   )))
3016          (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>")
3017                                                      1 font-lock-variable-name-face)) 'append)
3018          (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>")
3019                                                      1 font-lock-keyword-face)) 'append))
3020        (--each (buffer-list)
3021          (with-current-buffer it
3022            (when (and (eq major-mode 'emacs-lisp-mode)
3023                       (boundp 'font-lock-mode)
3024                       font-lock-mode)
3025              (font-lock-refresh-defaults)))))))
3026
3027 (provide 'dash)
3028 ;;; dash.el ends here