Create stand-alone anaphoric macros

- no need for lexical scope
 - support Emacs 23
master
Magnar Sveen 14 years ago
parent d2dfb11d01
commit 754dd0d1fb
  1. 51
      bang.el

@ -1,4 +1,4 @@
;;; bang.el --- A modern list library for Emacs -*- lexical-binding: t -*-
;;; bang.el --- A modern list library for Emacs
;; Copyright (C) 2012 Magnar Sveen, Joel McCracken
@ -33,8 +33,8 @@
(defun !reduce-from (fn initial-value list)
"Returns the result of applying FN to INITIAL-VALUE and the
first item in LIST, then applying FN to that result and the 2nd
item, etc. If INITIAL-VALUE contains no items, returns
INITIAL-VALUE and FN is not called."
item, etc. If LIST contains no items, returns INITIAL-VALUE and
FN is not called."
(let ((acc initial-value))
(while list
(setq acc (funcall fn acc (car list)))
@ -42,7 +42,18 @@ INITIAL-VALUE and FN is not called."
acc))
(defmacro !!reduce-from (form initial-value list)
`(!reduce-from (lambda (acc it) ,form) ,initial-value ,list))
"Anaphoric form of `!reduce'. Returns the result of applying
FORM to INITIAL-VALUE and the first item in LIST, then applying
FORM to that result and the 2nd item, etc. If INITIAL-VALUE
contains no items, returns INITIAL-VALUE and FORM is not called."
`(let ((!--list ,list)
(!--acc ,initial-value))
(while !--list
(let ((it (car !--list))
(acc !--acc))
(setq !--acc ,form))
(setq !--list (cdr !--list)))
!--acc))
(defun !reduce (fn list)
"Returns the result of applying FN to the first 2 items in LIST,
@ -55,7 +66,15 @@ LIST has only 1 item, it is returned and FN is not called."
(funcall fn)))
(defmacro !!reduce (form list)
`(!reduce (lambda (&optional acc it) ,form) ,list))
"Returns the result of applying FORM to the first 2 items in LIST,
then applying FORM to that result and the 3rd item, etc. If
LIST contains no items, FORM must accept no arguments as
well, and reduce returns the result of calling FORM with no
arguments. If LIST has only 1 item, it is returned and FORM
is not called."
(if (eval list)
`(!!reduce-from ,form ,(car (eval list)) ',(cdr (eval list)))
`(let (acc it) ,form)))
(defun !filter (fn list)
"Returns a new list of the items in LIST for which FN returns a non-nil value."
@ -67,13 +86,22 @@ LIST has only 1 item, it is returned and FN is not called."
(nreverse result)))
(defmacro !!filter (form list)
`(!filter (lambda (it) ,form) ,list))
"Returns a new list of the items in LIST for which FORM returns a non-nil value."
`(let ((!--list ,list)
(!--result '()))
(while !--list
(let ((it (car !--list)))
(when ,form
(setq !--result (cons it !--result))))
(setq !--list (cdr !--list)))
(nreverse !--result)))
(defun !remove (fn list)
"Returns a new list of the items in LIST for which FN returns nil."
(!!filter (not (funcall fn it)) list))
(defmacro !!remove (form list)
"Returns a new list of the items in LIST for which FORM returns nil."
`(!!filter (not ,form) ,list))
(defun !concat (&rest lists)
@ -87,7 +115,9 @@ Thus function FN should return a collection."
(apply '!concat (!map fn list)))
(defmacro !!mapcat (form list)
`(!mapcat (lambda (it) ,form) ,list))
"Returns the result of applying concat to the result of applying map to FORM and LIST.
Thus function FORM should return a collection."
`(apply '!concat (!!map ,form ,list)))
(defalias '!partial 'apply-partially)
@ -95,12 +125,7 @@ Thus function FN should return a collection."
"Return a new list with all duplicates removed.
The test for equality is done with `equal',
or with `!compare-fn' if that's non-nil."
(let ((result '()))
(while list
(when (not (!contains? result (car list)))
(setq result (cons (car list) result)))
(setq list (cdr list)))
(nreverse result)))
(!!filter (not (!contains? !--result it)) list))
(defun !intersection (list list2)
"Return a new list containing only the elements that are members of both LIST and LIST2.

Loading…
Cancel
Save