From 4c31b0b94489156a2228cf53a2175719f9aacf0b Mon Sep 17 00:00:00 2001 From: fiddlerwoaroof Date: Sun, 13 Aug 2017 12:49:23 -0700 Subject: [PATCH] Initial commit --- .gitignore | 1 + data-lens.asd | 8 ++++++ lens.lisp | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 .gitignore create mode 100644 data-lens.asd create mode 100644 lens.lisp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be303db --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.fasl diff --git a/data-lens.asd b/data-lens.asd new file mode 100644 index 0000000..8cfad8c --- /dev/null +++ b/data-lens.asd @@ -0,0 +1,8 @@ +(asdf:defsystem #:data-lens + :description "Utilities for building data transormations from composable functions, modeled on lenses and transducers" + :author "Edward Langley " + :license "MIT" + :depends-on (cl-ppcre) + :serial t + :components ((:file "lens"))) + diff --git a/lens.lisp b/lens.lisp new file mode 100644 index 0000000..3cdc0f9 --- /dev/null +++ b/lens.lisp @@ -0,0 +1,75 @@ +(defpackage :data-lens + (:use :cl) + (:export #:regex-match #:include #:exclude #:pick + #:snapshot-to-vector #:vector-to-lt #:key-transform + #:combine #:derive #:cumsum #:over #:on #:shortcut + #:defun-ct)) +(in-package :data-lens) + +(defmacro shortcut (name function &body bound-args) + `(eval-when (:load-toplevel :compile-toplevel :execute) + (setf (fdefinition ',name) + (,function ,@bound-args)))) + +(defmacro defun-ct (name (&rest args) &body body) + `(eval-when (:load-toplevel :compile-toplevel :execute) + (defun ,name ,args + ,@body))) + +(defun-ct regex-match (regex) + (lambda (data) + (cl-ppcre:scan-to-strings regex data))) + +(defun-ct include (pred) + (lambda (seq) + (remove-if-not pred seq))) + +(defun-ct exclude (pred) + (lambda (seq) + (remove-if pred seq))) + +(defun-ct pick (selector) + (lambda (seq) + (map 'list selector seq))) + +(defun-ct key-transform (fun key-get key-set) + (lambda (it) + (let ((key-val (funcall key-get it))) + (funcall key-set + (funcall fun key-val))))) + +(defun-ct combine (fun1 fun2) + (lambda (item) + (list (funcall fun1 item) + (funcall fun2 item)))) + +(defun-ct derive (diff-fun &key (key #'identity)) + (lambda (list) + (mapcar (lambda (next cur) + (cons (funcall diff-fun (funcall key next) (funcall key cur)) + next)) + (cdr list) + list))) + +(defun-ct cumsum (&key (add-fun #'+) (key #'identity) (combine (lambda (x y) y x)) (zero 0)) + (lambda (seq) + (nreverse + (reduce (lambda (accum next) + (let ((key-val (funcall key next)) + (old-val (if accum + (funcall key (car accum)) + zero))) + (cons (funcall combine + (funcall add-fun old-val key-val) + next) + accum))) + seq + :initial-value ())))) + +(defun-ct over (fun &key (result-type 'list)) + (lambda (seq) + (map result-type fun seq))) + +(defun-ct on (fun key) + (lambda (it) + (funcall fun (funcall key it))))