about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc/sequence.el
blob: a5428ef0444807d8acb570470c186b661a8ae383 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
;;; sequence.el --- Working with the "sequence" types -*- lexical-binding: t -*-
;; Author: William Carroll <wpcarro@gmail.com>

;;; Commentary:
;; Elisp supports a typeclass none as "sequence" which covers the following
;; types:
;; - list: '(1 2 3 4 5)
;; - vector: ["John" 27 :blue]
;; - string: "To be or not to be..."

;; TODO: Document the difference between a "reduce" and a "fold".  I.e. - reduce
;; has an initial value whereas fold uses the first element in the sequence as
;; the initial value.
;;
;; Note: This should be an approximation of Elixir's Enum protocol albeit
;; without streams.
;;
;; Elisp has done a lot of this work already and these are mostly wrapper
;; functions.
;; See the following list for reference:
;; - sequencep
;; - elt
;; - copy-sequence
;; - reverse
;; - nreverse
;; - sort
;; - seq-elt
;; - seq-length
;; - seqp
;; - seq-drop
;; - seq-take
;; - seq-take-while
;; - seq-drop-while
;; - seq-do
;; - seq-map
;; - seq-mapn
;; - seq-filter
;; - seq-remove
;; - seq-reduce
;; - seq-some
;; - seq-find
;; - seq-every-p
;; - seq-empty-p
;; - seq-count
;; - seq-sort
;; - seq-contains
;; - seq-position
;; - seq-uniq
;; - seq-subseq
;; - seq-concatenate
;; - seq-mapcat
;; - seq-partition
;; - seq-intersection
;; - seq-difference
;; - seq-group-by
;; - seq-into
;; - seq-min
;; - seq-max
;; - seq-doseq
;; - seq-let

;;; Code:

;; Perhaps we can provide default implementations for `filter' and `map' derived
;; from the `reduce' implementation.
;; (defprotocol sequence
;;   :functions (reduce))
;; (definstance sequence list
;;   :reduce #'list/reduce
;;   :filter #'list/filter
;;   :map    #'list/map)
;; (definstance sequence vector
;;   :reduce #'vector/reduce)
;; (definstance sequence string
;;   :reduce #'string)

(defun sequence/classify (xs)
  "Return the type of `XS'."
  (cond
   ((listp xs) 'list)
   ((vectorp xs) 'vector)
   ((stringp xs) 'string)))

(defun sequence/reduce (acc f xs)
  "Reduce of `XS' calling `F' on x and `ACC'."
  (seq-reduce
   (lambda (acc x)
     (funcall f x acc))
   xs
   acc))

;; Elixir also turned everything into a list for efficiecy reasons.

(defun sequence/filter (p xs)
  "Filter `XS' with predicate, `P'.
Returns a list regardless of the type of `XS'."
  (seq-filter p xs))

(defun sequence/map (f xs)
  "Maps `XS' calling `F' on each element.
Returns a list regardless of the type of `XS'."
  (seq-map f xs))

(provide 'sequence)
;;; sequence.el ends here