diff --git a/bang.el b/bang.el index 5b1bc50..1094f4e 100644 --- a/bang.el +++ b/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.