aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Okay <cbeok@protonmail.com>2020-07-13 08:32:45 -0500
committerColin Okay <cbeok@protonmail.com>2020-07-13 08:32:45 -0500
commit414a68d50ab084dec85dc9a2d4971464b83e4e99 (patch)
tree2717e4fb1a5fa5f0a1421a9118719fb469caacef
initial commit
-rw-r--r--lambda-tools.asd12
-rw-r--r--lambda-tools.lisp41
-rw-r--r--macros.lisp53
-rw-r--r--package.lisp6
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))