* 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 "")

;; Actually returns the first match
(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' is similar to `dolist', but works on all sequence types
(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))

;; similar to `mapc'
(seq-do #'print '(1 2 3 4))

;; similar to `mapcar'
(seq-map #'1+ '(1 2 3 4))
(seq-map #'1+ [1 2 3 4])
(seq-map #'1+ "Hello")

;; filtering/removing
(seq-filter #'oddp '(1 2 3 4))
(seq-remove #'oddp '[1 2 3 4])

;; Reducing
(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)

;; Supports gv.el
;; This is the only case of side effect in seq.el
(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))

;; Nested & on various sequence types
(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)

;; same support for gv.el as in seq.el
(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-keys-apply & map-values-apply


;; Return a copy of the original map
(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/