diff options
-rw-r--r-- | lambda-tools.asd | 12 | ||||
-rw-r--r-- | lambda-tools.lisp | 41 | ||||
-rw-r--r-- | macros.lisp | 53 | ||||
-rw-r--r-- | package.lisp | 6 |
4 files changed, 112 insertions, 0 deletions
diff --git a/lambda-tools.asd b/lambda-tools.asd new file mode 100644 index 0000000..90b2977 --- /dev/null +++ b/lambda-tools.asd @@ -0,0 +1,12 @@ +;;;; lambda-tools.asd + +(asdf:defsystem #:lambda-tools + :description "Describe lambda-tools here" + :author "Your Name <your.name@example.com>" + :license "Specify license here" + :version "0.0.1" + :serial t + :depends-on (:alexandria) + :components ((:file "package") + (:file "macros") + (:file "lambda-tools"))) diff --git a/lambda-tools.lisp b/lambda-tools.lisp new file mode 100644 index 0000000..4b3ec86 --- /dev/null +++ b/lambda-tools.lisp @@ -0,0 +1,41 @@ +;;;; lambda-tools.lisp + +(in-package #:lambda-tools) + +(defun $or (&rest predicates) + "Each argument in PREDICATES is a predicate function of one +argument. Returns a new predicate, call it P, that is the +disjunction of each of the PREDICATES. + +The value of (P X) is the value of the first predicate Q in PREDICATES +such that (Q X) is non-NIL, or is NIL if none of the PREDICATES return +non-NIL. + +That is, the disjuction of PREDICATES is short-circuiting. If any +PREDICATES have side effects, they will be executed only if each of +the preceding predicates in the list returned NIL." + (labels ((disj (x preds) + (if (null preds) nil + (if-let (res (funcall (car preds) x)) + res + (disj x (cdr preds)))))) + (lambda (x) (disj x predicates)))) + +(defun $and (&rest predicates) + "Each argument in PREDICATES is a predicate function of one +argument. Returns a new predicate of one argument, call it P, that is +the conjunction of each of the PREDICATES. + +The value of (P X) is NIL if any of the PREDICATES applied to X are +NIL. Otherwise it is the value of the last member in PREDICATES +applied to X. + +That is, the conjunction of PREDICATES is short-circuiting. If any +PREDICATES have side effects, they will be executed only if each of +the preceding predicates in the list returned non-NIL." + (labels ((conj (x preds) + (cond ((null preds) t) + ((null (cdr preds)) (funcall (car preds) x)) + ((funcall (car preds) x) + (conj x (cdr preds)))))) + (lambda (x) (conj x predicates)))) diff --git a/macros.lisp b/macros.lisp new file mode 100644 index 0000000..cee6eb5 --- /dev/null +++ b/macros.lisp @@ -0,0 +1,53 @@ +(in-package :lambda-tools) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun is-substitute-var (symbol) + (and (symbolp symbol) + (eq (elt (symbol-name symbol) 0) + #\_)))) + + + + + +(defmacro $ (expr) +"Quickly create functions from an expression EXPR with 'blanks' in +it. Each blank is a symbol that betins with the underscore _. Symbols +with the same name are treated as the same variable. + +A function is returned, it accepts exactly the number of variables as +there were unique blanks in the expression. When calling the new +function, the variables are bound in the order they appeared in EXPR. + +> (macroexpand-1 '($ (+ _a (* _b 3) _b (- _a _c) 10))) + (LAMBDA (_A _B _C) + (+ _A + (* _B 3) + _B + (- _A _C) + 10)) + +The macro is useful for succinctly passing functions to +higher order functions: + +> (mapcar ($ (+ _ 10)) '(1 2 3 4)) + (11 12 13 14) + +> (let ((elt-num 2)) + (mapcar ($ (elt _ elt-num)) + (list \"hey dude\" + #(1 2 3 4) + \"ffffffffff\"))) + (#\y 3 #\f) +" + (let ((new-params (list))) + (subst-if t (constantly nil) expr + :key (lambda (x) (when (is-substitute-var x) + (pushnew x new-params)))) + `(lambda ,(reverse new-params) ,expr))) + + + + + + diff --git a/package.lisp b/package.lisp new file mode 100644 index 0000000..0dcbc8f --- /dev/null +++ b/package.lisp @@ -0,0 +1,6 @@ +;;;; package.lisp + +(defpackage #:lambda-tools + (:use #:cl) + (:import-from #:alexandria + #:if-let)) |