[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/dash d2dfb11 023/439: Use double-bang for anaphoric fun
From: |
Phillip Lord |
Subject: |
[elpa] externals/dash d2dfb11 023/439: Use double-bang for anaphoric functions |
Date: |
Tue, 04 Aug 2015 20:25:58 +0000 |
branch: externals/dash
commit d2dfb11d01ac92bc234dd030e8511938272a4294
Author: Magnar Sveen <address@hidden>
Commit: Magnar Sveen <address@hidden>
Use double-bang for anaphoric functions
---
README.md | 8 ++--
bang.el | 134 ++++++++++++++++++++++++++++++-------------------------------
tests.el | 67 ++++++++++++++++++------------
3 files changed, 110 insertions(+), 99 deletions(-)
diff --git a/README.md b/README.md
index fd3b3ca..1f18676 100644
--- a/README.md
+++ b/README.md
@@ -10,13 +10,13 @@ This is so much a work in progress that you should
definitely not be using it ye
## Anaphoric functions
-While `!filter` takes a function to filter the list by, you can also pass
-it a form - which will then be executed with `it` exposed as the list item.
-Here's an example:
+While `!filter` takes a function to filter the list by, you can also use the
+anaphoric form with double bangs - which will then be executed with `it`
exposed
+as the list item. Here's an example:
(!filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) ;; normal version
- (!filter (= 0 (% it 2)) '(1 2 3 4)) ;; anaphoric version
+ (!!filter (= 0 (% it 2)) '(1 2 3 4)) ;; anaphoric version
of course the original can also be written like
diff --git a/bang.el b/bang.el
index 085f76f..5b1bc50 100644
--- a/bang.el
+++ b/bang.el
@@ -1,4 +1,4 @@
-;;; bang.el --- A modern list library for Emacs
+;;; bang.el --- A modern list library for Emacs -*- lexical-binding: t -*-
;; Copyright (C) 2012 Magnar Sveen, Joel McCracken
@@ -25,96 +25,94 @@
;;; Code:
-(defun !--call-with-it (form-or-fn)
- (if (functionp form-or-fn)
- (list form-or-fn 'it)
- form-or-fn))
-
-(defmacro !map (form-or-fn list)
- "Returns a new list consisting of the result of applying
-FORM-OR-FN to the items in list."
- (if (functionp form-or-fn)
- `(mapcar #',form-or-fn ,list)
- `(mapcar #'(lambda (it) ,form-or-fn) ,list)))
-
-(defmacro !reduce-from (form-or-fn initial-value list)
- "Returns the result of applying FORM-OR-FN to INITIAL-VALUE and
-the first item in LIST, then applying FORM-OR-FN to that result
-and the 2nd item, etc. If INITIAL-VALUE contains no items,
-returns INITIAL-VALUE and FORM-OR-FN is not called."
- `(let ((!--list ,list)
- (!--acc ,initial-value))
- (while !--list
- (let ((it (car !--list))
- (acc !--acc))
- (setq !--acc ,(if (functionp form-or-fn) (list form-or-fn 'acc 'it)
form-or-fn))
- (setq !--list (cdr !--list))))
- !--acc))
-
-(defmacro !reduce (form-or-fn list)
- "Returns the result of applying FORM-OR-FN to the first 2 items in LIST,
-then applying FORM-OR-FN to that result and the 3rd item, etc. If
-LIST contains no items, FORM-OR-FN must accept no arguments as
-well, and reduce returns the result of calling FORM-OR-FN with no
-arguments. If LIST has only 1 item, it is returned and FORM-OR-FN
-is not called."
- (if (eval list)
- `(!reduce-from ,form-or-fn ,(car (eval list)) ',(cdr (eval list)))
- (if (functionp form-or-fn)
- (list form-or-fn)
- `(let (acc it) ,form-or-fn))))
-
-(defmacro !filter (form-or-fn list)
- "Returns a new list of the items in LIST for which FORM-OR-FN returns a
non-nil value."
- `(let ((!--list ,list)
- (!--result '()))
- (while !--list
- (let ((it (car !--list)))
- (when ,(!--call-with-it form-or-fn)
- (setq !--result (cons it !--result))))
- (setq !--list (cdr !--list)))
- (nreverse !--result)))
-
-(defmacro !remove (form-or-fn list)
- "Returns a new list of the items in LIST for which FORM-OR-FN returns nil."
- `(!filter (not ,(!--call-with-it form-or-fn)) ,list))
-
-(defalias '!select '!filter)
-(defalias '!reject '!remove)
+(defalias '!map 'mapcar)
+
+(defmacro !!map (form list)
+ `(!map (lambda (it) ,form) ,list))
+
+(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."
+ (let ((acc initial-value))
+ (while list
+ (setq acc (funcall fn acc (car list)))
+ (setq list (cdr list)))
+ acc))
+
+(defmacro !!reduce-from (form initial-value list)
+ `(!reduce-from (lambda (acc it) ,form) ,initial-value ,list))
+
+(defun !reduce (fn list)
+ "Returns the result of applying FN to the first 2 items in LIST,
+then applying FN to that result and the 3rd item, etc. If LIST
+contains no items, FN must accept no arguments as well, and
+reduce returns the result of calling FN with no arguments. If
+LIST has only 1 item, it is returned and FN is not called."
+ (if list
+ (!reduce-from fn (car list) (cdr list))
+ (funcall fn)))
+
+(defmacro !!reduce (form list)
+ `(!reduce (lambda (&optional acc it) ,form) ,list))
+
+(defun !filter (fn list)
+ "Returns a new list of the items in LIST for which FN returns a non-nil
value."
+ (let ((result '()))
+ (while list
+ (when (funcall fn (car list))
+ (setq result (cons (car list) result)))
+ (setq list (cdr list)))
+ (nreverse result)))
+
+(defmacro !!filter (form list)
+ `(!filter (lambda (it) ,form) ,list))
+
+(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)
+ `(!!filter (not ,form) ,list))
(defun !concat (&rest lists)
"Returns a new list with the concatenation of the elements in
the supplied LISTS."
(apply 'append (append lists '(nil))))
-(defmacro !partial (fn &rest args)
- "Takes a function FN and fewer than the normal arguments to FN, and
- returns a fn that takes a variable number of additional ARGS. When
- called, the returned function calls FN with args + additional args."
- `(apply-partially ',fn ,@args))
-
-(defmacro !mapcat (fn list)
+(defun !mapcat (fn list)
"Returns the result of applying concat to the result of applying map to FN
and LIST.
Thus function FN should return a collection."
- `(apply '!concat (!map ,fn ,list)))
+ (apply '!concat (!map fn list)))
+
+(defmacro !!mapcat (form list)
+ `(!mapcat (lambda (it) ,form) ,list))
+
+(defalias '!partial 'apply-partially)
(defun !uniq (list)
"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."
- (!filter (not (!contains? !--result it)) list))
+ (let ((result '()))
+ (while list
+ (when (not (!contains? result (car list)))
+ (setq result (cons (car list) result)))
+ (setq list (cdr list)))
+ (nreverse result)))
(defun !intersection (list list2)
"Return a new list containing only the elements that are members of both
LIST and LIST2.
The test for equality is done with `equal',
or with `!compare-fn' if that's non-nil."
- (!filter (!contains? list2 it) list))
+ (!!filter (!contains? list2 it) list))
(defun !difference (list list2)
"Return a new list with only the members of LIST that are not in LIST2.
The test for equality is done with `equal',
or with `!compare-fn' if that's non-nil."
- (!filter (not (!contains? list2 it)) list))
+ (!!filter (not (!contains? list2 it)) list))
(defun !contains? (list element)
"Return whether LIST contains ELEMENT.
diff --git a/tests.el b/tests.el
index 9bce0f3..a197849 100644
--- a/tests.el
+++ b/tests.el
@@ -7,70 +7,82 @@
(ert-deftest map ()
"`!map' returns a new list with the results of calling the function on each
element."
(should (equal (!map (lambda (num) (* num num)) '(1 2 3 4)) '(1 4 9 16)))
- (should (equal (!map (* it it) '(1 2 3 4)) '(1 4 9 16)))
- (should (equal (!map square '(1 2 3 4)) '(1 4 9 16))))
+ (should (equal (!map 'square '(1 2 3 4)) '(1 4 9 16)))
+ (should (equal (!!map (* it it) '(1 2 3 4)) '(1 4 9 16)))
+ )
-(ert-deftest reduce ()
- "`!reduce' takes a list and applies the function over them to create one
result"
- (should (equal (!reduce + '()) 0))
- (should (equal (!reduce + '(1)) 1))
- (should (equal (!reduce + '(1 2)) 3))
- (should (equal (!reduce-from + 7 '()) 7))
- (should (equal (!reduce-from + 7 '(1)) 8))
- (should (equal (!reduce-from + 7 '(1 2)) 10))
+(ert-deftest reduce-from ()
+ "`!reduce-from' takes a list and an initial value, and applies the function
over them to create one result"
+ (should (equal (!reduce '+ '()) 0))
+ (should (equal (!reduce '+ '(1)) 1))
+ (should (equal (!reduce '+ '(1 2)) 3))
+ (should (equal (!reduce-from '+ 7 '()) 7))
+ (should (equal (!reduce-from '+ 7 '(1)) 8))
+ (should (equal (!reduce-from '+ 7 '(1 2)) 10))
+ (should (equal (!!reduce-from (+ acc it) 7 '(1 2 3)) 13))
+ )
+(ert-deftest reduce ()
+ "`!reduce' takes a list and applies the function over the elements to create
one result"
(should (equal (!reduce (lambda (memo item) (format "%s-%s" memo item)) '(1
2 3)) "1-2-3"))
- (should (equal (!reduce (format "%s-%s" acc it) '(1 2 3)) "1-2-3"))
- (should (equal (!reduce (format "%s-%s" acc it) '()) "nil-nil")))
+ (should (equal (!!reduce (format "%s-%s" acc it) '(1 2 3)) "1-2-3"))
+ (should (equal (!!reduce (format "%s-%s" acc it) '()) "nil-nil"))
+ )
(ert-deftest filter ()
"`!filter' returns a new list of only those elements where the predicate was
non-nil."
(should (equal (!filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) '(2 4)))
- (should (equal (!filter (= 0 (% it 2)) '(1 2 3 4)) '(2 4)))
- (should (equal (!filter even? '(1 2 3 4)) '(2 4)))
- (should (equal (!select even? '(1 2 3 4)) '(2 4))))
+ (should (equal (!filter 'even? '(1 2 3 4)) '(2 4)))
+ (should (equal (!!filter (= 0 (% it 2)) '(1 2 3 4)) '(2 4)))
+ )
(ert-deftest remove ()
"`!remove' returns a new list of only those elements where the predicate was
nil."
(should (equal (!remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) '(1 3)))
- (should (equal (!remove (= 0 (% it 2)) '(1 2 3 4)) '(1 3)))
- (should (equal (!remove even? '(1 2 3 4)) '(1 3)))
- (should (equal (!reject even? '(1 2 3 4)) '(1 3))))
+ (should (equal (!remove 'even? '(1 2 3 4)) '(1 3)))
+ (should (equal (!!remove (= 0 (% it 2)) '(1 2 3 4)) '(1 3)))
+ )
(ert-deftest concat ()
"`!concat' returns the concatenation of the elements in the supplied lists"
(should (equal (!concat) nil))
(should (equal (!concat '(1)) '(1)))
(should (equal (!concat '(1) '(2)) '(1 2)))
- (should (equal (!concat '(1) '(2 3) '(4)) '(1 2 3 4))))
+ (should (equal (!concat '(1) '(2 3) '(4)) '(1 2 3 4)))
+ )
(ert-deftest mapcat ()
"`!mapcat' applies the function to all elements of the list and then
concatenates the result"
- (should (equal (!mapcat list '(1 2 3)) '(1 2 3)))
+ (should (equal (!mapcat 'list '(1 2 3)) '(1 2 3)))
(should (equal (!mapcat (lambda (item) (list 0 item)) '(1 2 3)) '(0 1 0 2 0
3)))
- (should (equal (!mapcat (list 0 it) '(1 2 3)) '(0 1 0 2 0 3))))
+ (should (equal (!!mapcat (list 0 it) '(1 2 3)) '(0 1 0 2 0 3)))
+ )
(ert-deftest partial ()
"`!partial' returns a function like fn where the first arguments are filled
in"
- (should (equal (funcall (!partial + 5) 3) 8))
- (should (equal (funcall (!partial + 5 2) 3) 10)))
+ (should (equal (funcall (!partial '+ 5) 3) 8))
+ (should (equal (funcall (!partial '+ 5 2) 3) 10))
+ )
(ert-deftest difference ()
"`!difference' returns a new list of only elements in list1 that are not in
list2."
(should (equal (!difference '() '()) '()))
(should (equal (!difference '(1 2 3) '(4 5 6)) '(1 2 3)))
- (should (equal (!difference '(1 2 3 4) '(3 4 5 6)) '(1 2))))
+ (should (equal (!difference '(1 2 3 4) '(3 4 5 6)) '(1 2)))
+ )
(ert-deftest intersection ()
"`!intersection' returns a new list of only elements that are in both given
lists."
(should (equal (!intersection '() '()) '()))
(should (equal (!intersection '(1 2 3) '(4 5 6)) '()))
- (should (equal (!intersection '(1 2 3 4) '(3 4 5 6)) '(3 4))))
+ (should (equal (!intersection '(1 2 3 4) '(3 4 5 6)) '(3 4)))
+ )
(ert-deftest uniq ()
"`!uniq' returns a new list of only unique elements."
(should (equal (!uniq '()) '()))
- (should (equal (!uniq '(1 2 2 4)) '(1 2 4))))
+ (should (equal (!uniq '(1 2 2 4)) '(1 2 4)))
+ )
(ert-deftest contains? ()
"`!contains?' returns t if the list contains the element."
@@ -78,4 +90,5 @@
(should (!contains? '(1 2 3) 2))
(should (not (!contains? '() '())))
(should (not (!contains? '() 1)))
- (should (not (!contains? '(1 2 4) 3))))
+ (should (not (!contains? '(1 2 4) 3)))
+ )
- [elpa] externals/dash f5b16e3 018/439: Make !partial have the same quote-less API as the rest of bang., (continued)
- [elpa] externals/dash f5b16e3 018/439: Make !partial have the same quote-less API as the rest of bang., Phillip Lord, 2015/08/04
- [elpa] externals/dash a02b6c1 021/439: Add note about no 'cl required., Phillip Lord, 2015/08/04
- [elpa] externals/dash 07de30e 019/439: !mapcat macro, and with that: goodbye 'cl!, Phillip Lord, 2015/08/04
- [elpa] externals/dash 52815c5 020/439: Add documentation, Phillip Lord, 2015/08/04
- [elpa] externals/dash 73204ca 022/439: Change !contains-p to !contains? to match clojure api., Phillip Lord, 2015/08/04
- [elpa] externals/dash 6c39876 003/439: Set up test framework with one basic test, Phillip Lord, 2015/08/04
- [elpa] externals/dash c0f2c8f 026/439: Test that it works with lexical binding., Phillip Lord, 2015/08/04
- [elpa] externals/dash 754dd0d 024/439: Create stand-alone anaphoric macros, Phillip Lord, 2015/08/04
- [elpa] externals/dash 9e74cc0 027/439: Remove dead code., Phillip Lord, 2015/08/04
- [elpa] externals/dash 8eab3d1 028/439: Slight improvements to map., Phillip Lord, 2015/08/04
- [elpa] externals/dash d2dfb11 023/439: Use double-bang for anaphoric functions,
Phillip Lord <=
- [elpa] externals/dash 85016d3 029/439: Fix quoted forms like `' in docs., Phillip Lord, 2015/08/04
- [elpa] externals/dash 6f0636f 032/439: Show only three first examples per function., Phillip Lord, 2015/08/04
- [elpa] externals/dash 4cc4147 035/439: Fix typo, Phillip Lord, 2015/08/04
- [elpa] externals/dash 41d77ec 034/439: Add function list to readme., Phillip Lord, 2015/08/04
- [elpa] externals/dash 214a7db 030/439: Quote and lowercase parameter names in docstring., Phillip Lord, 2015/08/04
- [elpa] externals/dash ec27b47 025/439: Turn tests into examples that can both be tested and turned into docs, Phillip Lord, 2015/08/04
- [elpa] externals/dash 1997e52 031/439: Treat dashes in docstring better., Phillip Lord, 2015/08/04
- [elpa] externals/dash 78fc2a3 038/439: Quote and downcase params with digits in them too., Phillip Lord, 2015/08/04
- [elpa] externals/dash 06efd3c 039/439: Slight improvements to docs., Phillip Lord, 2015/08/04
- [elpa] externals/dash de5ff6a 037/439: Simplify quotes in readme., Phillip Lord, 2015/08/04