What's the equivalent of foldr, foldl in Emacs Lisp?

If you

(require 'cl)

then you can use the Common Lisp function reduce. Pass the keyword argument :from-end t for foldr.

ELISP> (reduce #'list '(1 2 3 4))
(((1 2) 3) 4)

ELISP> (reduce #'list '(1 2 3 4) :from-end t)
(1 (2 (3 4)))

Since Emacs-24.3 we recommend the use of cl-lib over cl (which is planned for removal in some distant future), so it would be:

(require 'cl-lib)
(cl-reduce #'+ '(1 2 3 4))

and since Emacs-25, you can also use the seq package for that:

(require 'seq)
(seq-reduce #'+ '(1 2 3 4) 0)

Common Lisp library provides plenty of sequence functions like mapping, filtering, folding, searching and even sorting. CL library is shipped with Emacs by default, so you should stick to it. I however really like dash.el library, because it provides enormous amounts of functions for list and tree manipulations. It also supports anaphoric macros and encourages functional programming, which makes code concise and elegant.

Haskell's folds correspond with dash.el folds:

  • foldl with -reduce-from
  • foldr with -reduce-r-from
  • foldl1 with -reduce
  • foldr1 with -reduce-r

Sum of a range 1 to 10 using folds might look like in this in Haskell and dash.el:

foldl (+) 0 [1..10] -- Haskell
(-reduce-from '+ 0 (number-sequence 1 10)) ; Elisp

You probably know, that folds are very general, and it is possible to implement maps and filters via folds. For example, to increment every element by 2, Haskell's currying and sections would allow for terse code, but in Elisp you would usually write verbose throwaway lambdas like that:

foldr ((:) . (+2)) [] [1..10] -- Haskell
(-reduce-r-from (lambda (x acc) (cons (+ x 2) acc)) '() (number-sequence 1 10)) ; Elisp

Guess what, it isn't necessary in dash.el with anaphoric macros, which allow special syntax by exposing variables of a lambda as shortcuts, like it and acc in folds. Anaphoric functions start with 2 dashes instead of 1:

(--reduce-r-from (cons (+ it 2) acc) '() (number-sequence 1 10))

There are plenty fold-like functions in dash.el:

;; Count elements matching a predicate
(-count 'evenp '(1 2 3 4 5)) ; 2
;; Add/multiply elements of a list together
(-sum '(1 2 3 4 5)) ; 15
(-product '(1 2 3 4 5)) ; 120
;; Find the smallest and largest element
(-min '(3 1 -1 2 4)) ; -1
(-max '(-10 0 10 5)) ; 10
;; Find smallest/largest with a custom rule (anaphoric versions)
(--min-by (> (length it) (length other)) '((1 2 3) (4 5) (6))) ; (6)
(--max-by (> (length it) (length other)) '((1 2 3) (4 5) (6))) ; (1 2 3)

Tags:

Emacs

Lisp

Elisp