* seq.el & map.el
(in Emacs 25.1)
Nicolas Petton
This slides are available online at
nicolas-petton.fr/presentations/emacsconf2015/
* Some words about me
Nicolas Petton
- Sotfware engineer working in Stockholm, Sweden
- I'm french
- Organizer of the Stockholm Emacs Meetup
- Maintainer or co-maintainer of several Emacs packages
(js2-refactor, seq.el, map.el, stream.el)
Web: nicolas-petton.fr
Email: nicolas@petton.fr
Twitter: @NicolasPetton
* What are seq.el and map.el?
** New libraries in Emacs 25.1
** Provides a high level API for collections
** Provides better support for vectors, hash-tables, etc.
_____________________________________________
| |
| Sequence |
| ______ ________________________________ |
| | | | | |
| | List | | Array | |
| | | | ________ ________ | |
| |______| | | | | | | |
| | | Vector | | String | | |
| | |________| |________| | |
| | ____________ _____________ | |
| | | | | | | |
| | | Char-table | | Bool-vector | | |
| | |____________| |_____________| | |
| |________________________________| |
|_____________________________________________|
* Why not dash.el?
** Dash only works with lists
** Dash includes other features
(such as threading macros, anaphoric macros, etc.)
** seq.el is extensible to new sequence implementations
* Quick overview of the seq.el
** seq.el works on sequence types: lists, vectors, and strings
** seq.el is extensible to new types
** All functions are prefixes with =seq-=
** All functions are free of side-effect
** All functions are tested in =seq-tests.el=
* seq.el & side-effects
** seq treats sequences as *values*
(No mutation of sequences)
** No side-effect
** Mapping, filtering, reversing return copies of the original sequences
* Examples
** Predicates
#+BEGIN_SRC elisp
(require 'seq)
(seq-p [2 4])
(seq-empty-p "")
(seq-some-p #'oddp '(1 2 3))
(seq-every-p #'evenp '(2 4 6))
(seq-contains-p "Hello" ?e)
#+END_SRC
** Iterating, mapping & filtering
#+BEGIN_SRC elisp
(seq-doseq (elt '(1 2 3 4))
(print elt))
(seq-doseq (elt [1 2 3 4])
(print elt))
(seq-doseq (elt "Hello world")
(print elt))
(seq-do #'print '(1 2 3 4))
(seq-map #'1+ '(1 2 3 4))
(seq-map #'1+ [1 2 3 4])
(seq-map #'1+ "Hello")
(seq-filter #'oddp '(1 2 3 4))
(seq-remove #'oddp '[1 2 3 4])
(seq-reduce #'+ [2 4 6] 0)
#+END_SRC
** Accessing elements
#+BEGIN_SRC elisp
(seq-elt [1 2 3 4] 2)
(seq-elt '(1 2 3 4) 2)
(seq-elt "Hello" 2)
(setf (seq-elt [1 2 3 4] 2) 6)
(seq-subseq "Hello" 0 4)
(seq-drop '(1 2 3 4) 2)
(seq-take [1 2 3 4] 2)
(seq-take-while #'oddp '(1 3 4))
(seq-drop-while #'oddp '(1 3 4))
#+END_SRC
** seq.el and pcase
*** Destructuring
#+BEGIN_SRC elisp
(seq-let (first _ third &rest rest) [1 2 3 4 5]
(message "First element: %s, third: %s, and rest: %s"
first third rest))
(seq-let (a (b (c))) [1 (2 "Hello")]
(message "a is: %s, b: %s, and c: %s" a b c))
#+END_SRC
*** Pattern matching
#+BEGIN_SRC elisp
(let ((myseq [1 2 3 4]))
(pcase myseq
((seq _ _ third) (message "%s" third))))
#+END_SRC
* Extending seq.el: stream.el
** stream.el provides a lazy seq implementation
** stream.el implements a new seq type: lazy seq, or streams
* What about map.el?
** Similar to seq.el, but for key/value data structures
** Currently supports alists, hash-tables and arrays
** In Emacs 25.1 (but not in ELPA)
** Unlike seq.el, =map-put= and =map-delete= have side-effect
* Examples
** Accessing map elements
- map-elt
- map-put
- map-delete
#+BEGIN_SRC elisp
(require 'map)
(map-elt '((a . 1) (b . 2))
'b)
(let ((ht (make-hash-table)))
(puthash 'a 2 ht)
(map-elt ht 'a))
(map-elt [10 11 12 13]
2)
(map-elt "Hello world"
3)
(let ((alist '((a . 1) (b . 2))))
(map-put alist 'b 3)
(map-elt alist 'b))
(map-put [a b c] 1 'd)
(setf (map-elt [a b c] 1) 'd)
#+END_SRC
** Predicates
#+BEGIN_SRC elisp
(map-p (make-hash-table))
(map-empty-p [])
(map-contains-key-p '((a . 1) (b . 2)) 'c)
(map-some-p (lambda (k v) (oddp v))
'((a . 1) (b . 2) (c . 3)))
(map-every-p (lambda (k v) (oddp v))
[1 3 5 7])
#+END_SRC
** Accessing keys, values, and nested elements
#+BEGIN_SRC elisp
(map-keys [a b c])
(map-values '((a . 1) (b . 2)))
(map-nested-elt '((a . ((c . 3))) (b . 2))
'(a c))
(map-nested-elt ["Hello" "World" ((a . 1))]
'(2 a))
#+END_SRC
** Iterating, mapping & filtering
#+BEGIN_SRC elisp
(map-apply (lambda (key value)
(message "Key: %s, value: %s" key value))
'((a . 1) (b . 2)))
(map-filter (lambda (k v) (oddp v))
'((a . 1) (b . 2) (c . 3) (d . 4)))
(map-remove (lambda (k v) (oddp v))
'((a . 1) (b . 2) (c . 3) (d . 4)))
#+END_SRC
** Destructuring & pcase
#+BEGIN_SRC elisp
(defvar mymap '((a . 1) (b . 2) (c . 3)))
(map-let (b c) mymap
(message "Value for key b is %s" b))
(map-let (('b val1)
('c val2))
mymap
(message "Value for key b is %s" val1))
(pcase mymap
((map a b) (message "Value for key a is %s" a)))
#+END_SRC
* Start using seq & map in your packages!
This slides are available online at
nicolas-petton.fr/presentations/emacsconf2015/