Browse code
make gh-pages branch
Ed Langley authored on 30/04/2019 06:47:55
Showing 98 changed files
Showing 98 changed files
- docs/Concept-index.html
- docs/Data-type-index.html
- docs/Definitions.html
- docs/Exported-definitions.html
- docs/Exported-functions.html
- docs/Exported-generic-functions.html
- docs/Exported-macros.html
- docs/Files.html
- docs/Function-index.html
- docs/Indexes.html
- docs/Internal-classes.html
- docs/Internal-definitions.html
- docs/Internal-functions.html
- docs/Internal-generic-functions.html
- docs/Internal-macros.html
- docs/Lisp-files.html
- docs/Packages.html
- README.org
- docs/Systems.html
- docs/The-data_002dlens-package.html
- docs/The-data_002dlens-system.html
- docs/The-data_002dlens_002flens_003cdot_003elisp-file.html
- docs/The-data_002dlens_003cdot_003easd-file.html
- docs/The-data_002dlens_003cdot_003elenses-package.html
- docs/Variable-index.html
- data-lens.asd
- docs/data-lens.texi
- docs/go-to-the-DATA_002dLENS-package.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eAPPLICABLE_002dWHEN-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eAPPLYING-macro.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eCOMBINE_002dMATCHING_002dLISTS-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eCOMPRESS_002dRUNS-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eCONS_002dNEW-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eCUMSUM-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eDEDUPLICATE-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eDEFUN_002dCT-macro.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eDENEST-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eDERIVE-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eELEMENT-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXCLUDE-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-COMMON_002dLISP_003ccolon_003e_003ccolon_003eHASH_002dTABLE-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-method.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-COMMON_002dLISP_003ccolon_003e_003ccolon_003eLIST-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-method.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-generic-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eFILLER-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eINCLUDE-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eJUXT-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eKEY-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eKEY_002dTRANSFORM-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eLET_002dFN-macro.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eMATCHING_002dLIST_002dREDUCER-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eMAXIMIZING-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eOF_002dLENGTH-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eOF_002dMAX_002dLENGTH-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eOF_002dMIN_002dLENGTH-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eON-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eOVER-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003ePICK-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eREGEX_002dMATCH-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eSHORTCUT-macro.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eSLICE-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eSORTED-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eSPLICE_002dELT-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eTRANSFORM_002dELT-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eTRANSFORM_002dHEAD-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eTRANSFORM_002dTAIL-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eUPDATE-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eUPDATEF-macro.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eZIPPING-function.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003e_003c_003e1-macro.html
- docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003e_003d_003e_003e-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES-package.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCLONE-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-AROUND-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCLONE-generic-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-class.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-COMMON_002dLISP_003ccolon_003e_003ccolon_003eLIST-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-COMMON_002dLISP_003ccolon_003e_003ccolon_003eVECTOR-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-generic-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-class.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dALIST_002dHISTORY_002dLENS-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dALIST_002dLENS-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dHASH_002dTABLE_002dLENS-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dPLIST_002dLENS-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eOVER-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eSET-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNCONSTANT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNCONSTANT-generic-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNIDENTITY-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-method.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNIDENTITY-generic-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eVIEW-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eWRAP_002dCONSTANT-function.html
- docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eWRAP_002dIDENTITY-function.html
- docs/go-to-the-data_002dlens-system.html
- docs/go-to-the-data_002dlens_002flens_003cdot_003elisp-file.html
- docs/go-to-the-data_002dlens_003cdot_003easd-file.html
- docs/index.html
- lens.lisp
52 | 52 |
deleted file mode 100644 |
... | ... |
@@ -1,26 +0,0 @@ |
1 |
-* Intro |
|
2 |
- |
|
3 |
-This library provides a language for expressing data manipulations as |
|
4 |
-the composition of more primitive operations. |
|
5 |
- |
|
6 |
-#+BEGIN_SRC lisp |
|
7 |
- DATA-LENS> (funcall (on (alexandria:compose |
|
8 |
- (over (transform-tail (over (slice 1)))) |
|
9 |
- (compress-runs :collector 'combine-matching-lists)) |
|
10 |
- (alexandria:compose |
|
11 |
- (over (juxt (element 0) |
|
12 |
- 'identity)) |
|
13 |
- (sorted 'char< |
|
14 |
- :key (element 0)))) |
|
15 |
- '("January" "February" "March" "April" |
|
16 |
- "May" "June" "July" "August" |
|
17 |
- "September" "October" "November" "December")) |
|
18 |
- #| ==> ((#\A "pril" "ugust") |
|
19 |
- (#\D "ecember") |
|
20 |
- (#\F "ebruary") |
|
21 |
- (#\J "anuary" "une" "uly") |
|
22 |
- (#\M "arch" "ay") |
|
23 |
- (#\N "ovember") |
|
24 |
- (#\O "ctober") |
|
25 |
- (#\S "eptember")) |# |
|
26 |
-#+END_SRC |
48 | 21 |
deleted file mode 100644 |
... | ... |
@@ -1,10 +0,0 @@ |
1 |
-(asdf:defsystem #:data-lens |
|
2 |
- :description "Utilities for building data transormations from composable functions, modeled on lenses and transducers" |
|
3 |
- :author "Edward Langley <el-cl@elangley.org>" |
|
4 |
- :license "MIT" |
|
5 |
- :depends-on (:cl-ppcre |
|
6 |
- :alexandria |
|
7 |
- :serapeum) |
|
8 |
- :serial t |
|
9 |
- :components ((:file "lens"))) |
|
10 |
- |
53 | 42 |
similarity index 100% |
54 | 43 |
rename from docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-COMMON_002dLISP_003ccolon_003e_003ccolon_003eHASH_002dTABLE-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-method.html |
55 | 44 |
rename to go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-COMMON_002dLISP_003ccolon_003e_003ccolon_003eHASH_002dTABLE-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-method.html |
56 | 45 |
similarity index 100% |
57 | 46 |
rename from docs/go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-COMMON_002dLISP_003ccolon_003e_003ccolon_003eLIST-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-method.html |
58 | 47 |
rename to go-to-the-DATA_002dLENS_003ccolon_003e_003ccolon_003eEXTRACT_002dKEY-COMMON_002dLISP_003ccolon_003e_003ccolon_003eLIST-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-method.html |
146 | 135 |
similarity index 100% |
147 | 136 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCLONE-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-AROUND-method.html |
148 | 137 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCLONE-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-AROUND-method.html |
155 | 144 |
similarity index 100% |
156 | 145 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-COMMON_002dLISP_003ccolon_003e_003ccolon_003eLIST-method.html |
157 | 146 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-COMMON_002dLISP_003ccolon_003e_003ccolon_003eLIST-method.html |
158 | 147 |
similarity index 100% |
159 | 148 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-COMMON_002dLISP_003ccolon_003e_003ccolon_003eVECTOR-method.html |
160 | 149 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-COMMON_002dLISP_003ccolon_003e_003ccolon_003eVECTOR-method.html |
161 | 150 |
similarity index 100% |
162 | 151 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-method.html |
163 | 152 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-method.html |
164 | 153 |
similarity index 100% |
165 | 154 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-method.html |
166 | 155 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eFMAP-COMMON_002dLISP_003ccolon_003e_003ccolon_003eT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-method.html |
173 | 162 |
similarity index 100% |
174 | 163 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dALIST_002dHISTORY_002dLENS-function.html |
175 | 164 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dALIST_002dHISTORY_002dLENS-function.html |
179 | 168 |
similarity index 100% |
180 | 169 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dHASH_002dTABLE_002dLENS-function.html |
181 | 170 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eMAKE_002dHASH_002dTABLE_002dLENS-function.html |
191 | 180 |
similarity index 100% |
192 | 181 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNCONSTANT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-method.html |
193 | 182 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNCONSTANT-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eCONSTANT_002d-method.html |
197 | 186 |
similarity index 100% |
198 | 187 |
rename from docs/go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNIDENTITY-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-method.html |
199 | 188 |
rename to go-to-the-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eUNIDENTITY-DATA_002dLENS_003cdot_003eLENSES_003ccolon_003e_003ccolon_003eIDENTITY_002d-method.html |
224 | 213 |
deleted file mode 100644 |
... | ... |
@@ -1,515 +0,0 @@ |
1 |
-(defpackage :data-lens.lenses |
|
2 |
- (:shadow :set) |
|
3 |
- (:use :cl) |
|
4 |
- (:export :over :set :view :make-alist-lens :make-plist-lens :make-hash-table-lens)) |
|
5 |
-(in-package :data-lens.lenses) |
|
6 |
- |
|
7 |
-#+fw.dev |
|
8 |
-(progn |
|
9 |
- ;; maybe functor implementation |
|
10 |
- (defclass maybe () |
|
11 |
- ()) |
|
12 |
- (defclass just (maybe) |
|
13 |
- ((%v :initarg :value :reader value))) |
|
14 |
- (defclass nothing (maybe) |
|
15 |
- ()) |
|
16 |
- |
|
17 |
- (defun just (value) |
|
18 |
- (make-instance 'just :value value)) |
|
19 |
- (defun nothing (&optional value) |
|
20 |
- (declare (ignore value)) |
|
21 |
- (make-instance 'nothing)) |
|
22 |
- |
|
23 |
- (defgeneric maybe (default value) |
|
24 |
- (:method (default (value just)) |
|
25 |
- (value value)) |
|
26 |
- (:method (default (value nothing)) |
|
27 |
- default)) |
|
28 |
- |
|
29 |
- (defgeneric maybe-apply (function value) |
|
30 |
- (:method (function (value just)) |
|
31 |
- (just (funcall function (value value)))) |
|
32 |
- (:method (function (value nothing)) |
|
33 |
- value)) |
|
34 |
- |
|
35 |
- (defmethod print-object ((o just) s) |
|
36 |
- (format s "#.(~s ~s)" |
|
37 |
- 'just |
|
38 |
- (value o))) |
|
39 |
- |
|
40 |
- (defmethod print-object ((o nothing) s) |
|
41 |
- (format s "#.(~s)" |
|
42 |
- 'nothing))) |
|
43 |
- |
|
44 |
-;; identity functor, necessary for set and over |
|
45 |
-(defclass identity- () |
|
46 |
- ((%v :initarg :value :reader unidentity))) |
|
47 |
- |
|
48 |
-(defun wrap-identity (v) |
|
49 |
- (make-instance 'identity- :value v)) |
|
50 |
- |
|
51 |
-(defmethod print-object ((o identity-) s) |
|
52 |
- (format s "#.(~s ~s)" |
|
53 |
- 'wrap-identity |
|
54 |
- (unidentity o))) |
|
55 |
- |
|
56 |
-;; constant functor, necessary for view |
|
57 |
-(defclass constant- () |
|
58 |
- ((%v :initarg :value :reader unconstant))) |
|
59 |
- |
|
60 |
-(defun wrap-constant (v) |
|
61 |
- (make-instance 'constant- :value v)) |
|
62 |
- |
|
63 |
-(defmethod print-object ((o constant-) s) |
|
64 |
- (format s "#.(~s ~s)" |
|
65 |
- 'wrap-constant |
|
66 |
- (unconstant o))) |
|
67 |
- |
|
68 |
-(defgeneric fmap (function data) |
|
69 |
- (:method (function (data identity-)) |
|
70 |
- (wrap-identity |
|
71 |
- (funcall function |
|
72 |
- (unidentity data)))) |
|
73 |
- (:method (function (data constant-)) |
|
74 |
- data) |
|
75 |
- (:method (function (data list)) |
|
76 |
- (mapcar function data)) |
|
77 |
- (:method (function (data vector)) |
|
78 |
- (map 'vector function data)) |
|
79 |
- #+fw.dev |
|
80 |
- (:method (function (data maybe)) |
|
81 |
- (maybe-apply function data))) |
|
82 |
- |
|
83 |
-(defun over (lens cb rec) |
|
84 |
- "Given a lens, a callback and a record, apply the lens to the |
|
85 |
-record, transform it by the callback and return copy of the record, |
|
86 |
-updated to contain the result of the callback. This is the fundamental |
|
87 |
-operation on a lens and SET and VIEW are implemented in terms of it. |
|
88 |
- |
|
89 |
-A lens is any function of the form (lambda (fun) (lambda (rec) ...)) |
|
90 |
-that obeys the lens laws (where == is some reasonable equality |
|
91 |
-operator): |
|
92 |
- |
|
93 |
- (== (view lens (set lens value rec)) |
|
94 |
- value) |
|
95 |
- |
|
96 |
- (== (set lens (view lens rec) rec) |
|
97 |
- rec) |
|
98 |
- |
|
99 |
- (== (set lens value2 (set lens value1 rec)) |
|
100 |
- (set lens value2 rec)) |
|
101 |
- |
|
102 |
-The inner lambda returns a functor that determines the policy to be |
|
103 |
-applied to the focused part. By default, this only uses IDENTITY- and |
|
104 |
-CONSTANT- in order to implement the lens operations over, set and |
|
105 |
-view. |
|
106 |
- |
|
107 |
-If these conditions are met, (over (data-lens:<>1 lens1 lens2) ...) is |
|
108 |
-equivalent to using lens2 to focus the part lens1 focuses: note that |
|
109 |
-composition is \"backwards\" from what one might expect: this is |
|
110 |
-because composition composes the wrapper lambdas and applies the |
|
111 |
-lambda that actually pulls a value out of a record later." |
|
112 |
- (unidentity |
|
113 |
- (funcall (funcall lens (lambda (x) (wrap-identity (funcall cb x)))) |
|
114 |
- rec))) |
|
115 |
- |
|
116 |
-(defun view (lens rec) |
|
117 |
- "Given a lens and a rec, return the focused value" |
|
118 |
- (unconstant |
|
119 |
- (funcall (funcall lens (lambda (x) (wrap-constant x))) |
|
120 |
- rec))) |
|
121 |
- |
|
122 |
-(defun set (lens v rec) |
|
123 |
- "Given a lens, a value and a rec, immutably update the rec to |
|
124 |
-contain the new value at the location focused by the lens." |
|
125 |
- (unidentity |
|
126 |
- (funcall (funcall lens (lambda (_) _ (wrap-identity v))) |
|
127 |
- rec))) |
|
128 |
- |
|
129 |
-#+fw.dev |
|
130 |
-(progn |
|
131 |
- ;; "fake" functors that don't assume a functor result to their |
|
132 |
- ;; callback |
|
133 |
- (defun over* (lens cb rec) |
|
134 |
- (funcall (funcall lens cb) |
|
135 |
- rec)) |
|
136 |
- |
|
137 |
- (defun set* (lens value rec) |
|
138 |
- (over lens |
|
139 |
- (lambda (_) |
|
140 |
- (declare (ignore _)) |
|
141 |
- value) |
|
142 |
- rec)) |
|
143 |
- |
|
144 |
- (defun view* (lens rec) |
|
145 |
- (over lens |
|
146 |
- (lambda (value) |
|
147 |
- (return-from view* |
|
148 |
- value)) |
|
149 |
- rec))) |
|
150 |
- |
|
151 |
-(defun make-alist-history-lens (key) |
|
152 |
- "A lens for updating a alist, preserving previous values" |
|
153 |
- (lambda (cb) |
|
154 |
- (lambda (alist) |
|
155 |
- (fmap (lambda (new) |
|
156 |
- (cons (cons key new) |
|
157 |
- alist)) |
|
158 |
- (funcall cb (serapeum:assocdr key alist)))))) |
|
159 |
- |
|
160 |
-(defun make-alist-lens (key) |
|
161 |
- "A lens for updating a alist, discarding previous values" |
|
162 |
- (lambda (cb) |
|
163 |
- (lambda (alist) |
|
164 |
- (fmap (lambda (new) |
|
165 |
- (remove-duplicates (cons (cons key new) |
|
166 |
- alist) |
|
167 |
- :key #'car |
|
168 |
- :from-end t)) |
|
169 |
- (funcall cb (serapeum:assocdr key alist)))))) |
|
170 |
- |
|
171 |
-(defun make-plist-lens (key) |
|
172 |
- "A lens for updating a plist, preserving previous values" |
|
173 |
- (lambda (cb) |
|
174 |
- (lambda (plist) |
|
175 |
- (fmap (lambda (new) |
|
176 |
- (list* key new |
|
177 |
- plist)) |
|
178 |
- (funcall cb (getf plist key)))))) |
|
179 |
- |
|
180 |
-(defun make-hash-table-lens (key) |
|
181 |
- "A lens for updating a hash-table, discarding previous values" |
|
182 |
- (lambda (cb) |
|
183 |
- (lambda (old-hash) |
|
184 |
- (fmap (lambda (new) |
|
185 |
- (let ((new-hash (alexandria:copy-hash-table old-hash))) |
|
186 |
- (prog1 new-hash |
|
187 |
- (setf (gethash key new-hash) |
|
188 |
- new)))) |
|
189 |
- (funcall cb (gethash key old-hash)))))) |
|
190 |
- |
|
191 |
-;; imagine a lens here that uses the MOP to immutably update a class... |
|
192 |
-(defgeneric clone (obj &rest new-initargs &key) |
|
193 |
- (:method :around (obj &rest new-initargs &key) |
|
194 |
- (apply #'reinitialize-instance (call-next-method) new-initargs))) |
|
195 |
- |
|
196 |
-#+fw.demo |
|
197 |
-(progn |
|
198 |
- (defclass foo () |
|
199 |
- ((a :initarg :a :accessor a))) |
|
200 |
- (defmethod clone ((obj foo) &key) |
|
201 |
- (make-instance 'foo :a (a obj))) |
|
202 |
- |
|
203 |
- ;;; needs to be updated for functor-based lens |
|
204 |
- (defun a-lens (cb) |
|
205 |
- (lambda (foo) |
|
206 |
- (fw.lu:prog1-bind (new (clone foo)) |
|
207 |
- (setf (a new) |
|
208 |
- (funcall cb (a foo)))))) |
|
209 |
- (view 'a-lens |
|
210 |
- (over 'a-lens '1+ |
|
211 |
- (set 'a-lens 2 |
|
212 |
- (make-instance 'foo :a 1)))) #| |
|
213 |
- ==> 3 |#) |
|
214 |
- |
|
215 |
- |
|
216 |
- |
|
217 |
-(defpackage :data-lens |
|
218 |
- (:use :cl) |
|
219 |
- (:import-from #:serapeum #:op #:defalias) |
|
220 |
- (:export #:regex-match #:include #:exclude #:pick #:key-transform |
|
221 |
- #:combine #:derive #:cumsum #:over #:on #:shortcut #:defun-ct #:key |
|
222 |
- #:extract-key #:element #:let-fn #:juxt #:transform-tail #:slice |
|
223 |
- #:compress-runs #:combine-matching-lists #:sorted #:applicable-when |
|
224 |
- #:of-length #:of-min-length #:of-max-length #:transform-head |
|
225 |
- #:maximizing #:zipping #:applying #:splice-elt #:transform-elt #:denest |
|
226 |
- #:op #:defalias #:<> #:<>1)) |
|
227 |
-(in-package :data-lens) |
|
228 |
- |
|
229 |
- |
|
230 |
-(declaim |
|
231 |
- (inline data-lens:over data-lens:transform-tail |
|
232 |
- data-lens:applicable-when data-lens:of-min-length |
|
233 |
- data-lens:on data-lens:over data-lens:slice |
|
234 |
- data-lens:compress-runs data-lens:combine-matching-lists |
|
235 |
- data-lens:juxt data-lens:element data-lens:sorted)) |
|
236 |
- |
|
237 |
-;;; TODO: consider making this wrap defalias? |
|
238 |
-(defmacro shortcut (name function &body bound-args) |
|
239 |
- `(eval-when (:load-toplevel :compile-toplevel :execute) |
|
240 |
- (setf (fdefinition ',name) |
|
241 |
- (,function ,@bound-args)))) |
|
242 |
- |
|
243 |
-(defmacro defun-ct (name (&rest args) &body body) |
|
244 |
- `(eval-when (:load-toplevel :compile-toplevel :execute) |
|
245 |
- (defun ,name ,args |
|
246 |
- ,@body))) |
|
247 |
- |
|
248 |
-(defmacro let-fn ((&rest bindings) &body body) |
|
249 |
- (let ((binding-forms (mapcar (lambda (form) |
|
250 |
- `(,(car form) ,(cadr form) |
|
251 |
- (funcall ,@(cddr form) ,@(cadr form)))) |
|
252 |
- bindings))) |
|
253 |
- `(labels ,binding-forms |
|
254 |
- ,@body))) |
|
255 |
- |
|
256 |
-(defgeneric extract-key (map key) |
|
257 |
- (:method ((map hash-table) key) |
|
258 |
- (gethash key map)) |
|
259 |
- (:method ((map list) key) |
|
260 |
- (typecase (car map) |
|
261 |
- (cons (cdr (assoc key map :test 'equal))) |
|
262 |
- (t (loop for (a-key . value) on map by #'cddr |
|
263 |
- when (equal key a-key) do |
|
264 |
- (return (car value))))))) |
|
265 |
- |
|
266 |
-(defun-ct deduplicate (&optional (test 'eql)) |
|
267 |
- (lambda (it) |
|
268 |
- (remove-duplicates it :test test))) |
|
269 |
- |
|
270 |
-(defun cons-new (&key (test 'eql) (key 'identity)) |
|
271 |
- (lambda (acc next) |
|
272 |
- (if (and acc |
|
273 |
- (funcall test |
|
274 |
- (funcall key (car acc)) |
|
275 |
- (funcall key next))) |
|
276 |
- acc |
|
277 |
- (cons next acc)))) |
|
278 |
- |
|
279 |
-(defun matching-list-reducer (test acc next) |
|
280 |
- (if (and acc |
|
281 |
- (funcall test (caar acc) (car next))) |
|
282 |
- (cons (cons (caar acc) |
|
283 |
- (append (cdar acc) |
|
284 |
- (cdr next))) |
|
285 |
- (cdr acc)) |
|
286 |
- (cons next acc))) |
|
287 |
- |
|
288 |
-(defun combine-matching-lists (&key (test 'eql) &allow-other-keys) |
|
289 |
- (lambda (acc next) |
|
290 |
- (matching-list-reducer test acc next))) |
|
291 |
- |
|
292 |
-(defun-ct compress-runs (&key (collector 'cons-new) (test 'eql) (key 'identity)) |
|
293 |
- (lambda (it) |
|
294 |
- (nreverse |
|
295 |
- (reduce (funcall collector :test test :key key) |
|
296 |
- it |
|
297 |
- :initial-value ())))) |
|
298 |
- |
|
299 |
-(defun-ct of-length (len) |
|
300 |
- (lambda (it) |
|
301 |
- (= (length it) |
|
302 |
- len))) |
|
303 |
- |
|
304 |
-(defun-ct of-min-length (len) |
|
305 |
- (lambda (it) |
|
306 |
- (>= (length it) |
|
307 |
- len))) |
|
308 |
- |
|
309 |
-(defun-ct of-max-length (len) |
|
310 |
- (lambda (it) |
|
311 |
- (>= (length it) |
|
312 |
- len))) |
|
313 |
- |
|
314 |
-(defun-ct applicable-when (fun test) |
|
315 |
- (lambda (it) |
|
316 |
- (if (funcall test it) |
|
317 |
- (funcall fun it) |
|
318 |
- it))) |
|
319 |
- |
|
320 |
-(defun-ct sorted (comparator &rest r &key key) |
|
321 |
- (declare (ignore key)) |
|
322 |
- (lambda (it) |
|
323 |
- (apply #'stable-sort (copy-seq it) comparator r))) |
|
324 |
- |
|
325 |
-(defun-ct element (num) |
|
326 |
- (lambda (it) |
|
327 |
- (elt it num))) |
|
328 |
- |
|
329 |
-(defun-ct key (key) |
|
330 |
- (lambda (map) |
|
331 |
- (declare (dynamic-extent map)) |
|
332 |
- (extract-key map key))) |
|
333 |
- |
|
334 |
-(defun-ct regex-match (regex) |
|
335 |
- (lambda (data) |
|
336 |
- (cl-ppcre:scan-to-strings regex data))) |
|
337 |
- |
|
338 |
-(defun-ct include (pred) |
|
339 |
- (lambda (seq) |
|
340 |
- (remove-if-not pred seq))) |
|
341 |
- |
|
342 |
-(defun-ct exclude (pred) |
|
343 |
- (lambda (seq) |
|
344 |
- (remove-if pred seq))) |
|
345 |
- |
|
346 |
-(defun-ct pick (selector) |
|
347 |
- (lambda (seq) |
|
348 |
- (map 'list selector seq))) |
|
349 |
- |
|
350 |
-(defun slice (start &optional end) |
|
351 |
- (lambda (it) |
|
352 |
- (subseq it start end))) |
|
353 |
- |
|
354 |
-(defun-ct update (thing fun &rest args) |
|
355 |
- (apply fun thing args)) |
|
356 |
- |
|
357 |
-(define-modify-macro updatef (fun &rest args) |
|
358 |
- update) |
|
359 |
- |
|
360 |
-(defun-ct transform-head (fun) |
|
361 |
- (lambda (it) |
|
362 |
- (typecase it |
|
363 |
- (list (list* (funcall fun (car it)) |
|
364 |
- (cdr it))) |
|
365 |
- (vector (let ((result (copy-seq it))) |
|
366 |
- (prog1 result |
|
367 |
- (updatef (elt result 0) fun))))))) |
|
368 |
- |
|
369 |
-(defun-ct transform-tail (fun) |
|
370 |
- (lambda (it) |
|
371 |
- (typecase it |
|
372 |
- (list (list* (car it) |
|
373 |
- (funcall fun (cdr it)))) |
|
374 |
- (vector (let ((result (copy-seq it))) |
|
375 |
- (prog1 result |
|
376 |
- (updatef (subseq result 1) |
|
377 |
- fun))))))) |
|
378 |
- |
|
379 |
-(defun-ct splice-elt (elt fun) |
|
380 |
- (lambda (it) |
|
381 |
- (append (subseq it 0 elt) |
|
382 |
- (funcall fun (nth elt it)) |
|
383 |
- (subseq it (1+ elt))))) |
|
384 |
- |
|
385 |
-(defun-ct transform-elt (elt fun) |
|
386 |
- (lambda (it) |
|
387 |
- (append (subseq it 0 elt) |
|
388 |
- (list (funcall fun (nth elt it))) |
|
389 |
- (subseq it (1+ elt))))) |
|
390 |
- |
|
391 |
-(defun-ct key-transform (fun key-get key-set) |
|
392 |
- (lambda (it) |
|
393 |
- (let ((key-val (funcall key-get it))) |
|
394 |
- (funcall key-set |
|
395 |
- (funcall fun key-val))))) |
|
396 |
- |
|
397 |
-(defun-ct juxt (fun1 &rest r) |
|
398 |
- (lambda (&rest args) |
|
399 |
- (list* (apply fun1 args) |
|
400 |
- (when r |
|
401 |
- (mapcar (lambda (f) |
|
402 |
- (apply f args)) |
|
403 |
- r))))) |
|
404 |
- |
|
405 |
-(defun =>> (fun1 fun2) |
|
406 |
- (lambda (i) |
|
407 |
- (prog1 (funcall fun1 i) |
|
408 |
- (funcall fun2)))) |
|
409 |
- |
|
410 |
-(defun-ct derive (diff-fun &key (key #'identity)) |
|
411 |
- (lambda (seq) |
|
412 |
- (typecase seq |
|
413 |
- (list (cons (cons nil (car seq)) |
|
414 |
- (mapcar (lambda (next cur) |
|
415 |
- (cons (funcall diff-fun |
|
416 |
- (funcall key next) |
|
417 |
- (funcall key cur)) |
|
418 |
- next)) |
|
419 |
- (cdr seq) |
|
420 |
- seq))) |
|
421 |
- (vector (coerce (loop for cur = nil then next |
|
422 |
- for next across seq |
|
423 |
- if cur |
|
424 |
- collect (cons (funcall diff-fun |
|
425 |
- (funcall key next) |
|
426 |
- (funcall key cur)) |
|
427 |
- cur) |
|
428 |
- else collect (cons nil next)) |
|
429 |
- 'vector))))) |
|
430 |
- |
|
431 |
-(defun-ct cumsum |
|
432 |
- (&key (add-fun #'+) (key #'identity) (combine (lambda (x y) y x)) (zero 0)) |
|
433 |
- (lambda (seq) |
|
434 |
- (nreverse |
|
435 |
- (reduce (lambda (accum next) |
|
436 |
- (let ((key-val (funcall key next)) |
|
437 |
- (old-val (if accum |
|
438 |
- (funcall key (car accum)) |
|
439 |
- zero))) |
|
440 |
- (cons (funcall combine |
|
441 |
- (funcall add-fun old-val key-val) |
|
442 |
- next) |
|
443 |
- accum))) |
|
444 |
- seq |
|
445 |
- :initial-value ())))) |
|
446 |
- |
|
447 |
-(defun-ct over (fun &key (result-type 'list)) |
|
448 |
- (lambda (seq) |
|
449 |
- (map result-type fun seq))) |
|
450 |
- |
|
451 |
-(defun-ct denest (&key (result-type 'list)) |
|
452 |
- (lambda (seq) |
|
453 |
- (apply #'concatenate result-type |
|
454 |
- seq))) |
|
455 |
- |
|
456 |
-(defmacro applying (fun &rest args) |
|
457 |
- (alexandria:with-gensyms (seq) |
|
458 |
- `(lambda (,seq) |
|
459 |
- (apply ,fun ,@args ,seq)))) |
|
460 |
- |
|
461 |
-(defun-ct on (fun key) |
|
462 |
- (lambda (it) |
|
463 |
- (funcall fun (funcall key it)))) |
|
464 |
- |
|
465 |
-(defun filler (length1 length2 fill-value) |
|
466 |
- (if (< length1 length2) |
|
467 |
- (make-sequence 'vector (- length2 length1) :initial-element fill-value) |
|
468 |
- #())) |
|
469 |
- |
|
470 |
-(defun-ct zipping (result-type &key (fill-value nil fill-value-p)) |
|
471 |
- (lambda (seq1 seq2) |
|
472 |
- (let ((length1 (when fill-value-p (length seq1))) |
|
473 |
- (length2 (when fill-value-p (length seq2)))) |
|
474 |
- (let ((seq1 (if fill-value-p |
|
475 |
- (concatenate result-type |
|
476 |
- seq1 |
|
477 |
- (filler length1 length2 fill-value)) |
|
478 |
- seq1)) |
|
479 |
- (seq2 (if fill-value-p |
|
480 |
- (concatenate result-type |
|
481 |
- seq2 |
|
482 |
- (filler length2 length1 fill-value)) |
|
483 |
- seq2))) |
|
484 |
- (map result-type #'list |
|
485 |
- seq1 seq2))))) |
|
486 |
- |
|
487 |
-(defun-ct maximizing (relation measure) |
|
488 |
- (lambda (it) |
|
489 |
- (let ((it-length (length it))) |
|
490 |
- (when (> it-length 0) |
|
491 |
- (values-list |
|
492 |
- (reduce (lambda (|arg1764| |arg1765|) |
|
493 |
- (destructuring-bind (cur-max max-idx) |arg1764| |
|
494 |
- (destructuring-bind (next next-idx) |arg1765| |
|
495 |
- (if (funcall relation (funcall measure cur-max) (funcall measure next)) |
|
496 |
- (list next next-idx) |
|
497 |
- (list cur-max max-idx))))) |
|
498 |
- (funcall (zipping 'vector) |
|
499 |
- it |
|
500 |
- (alexandria:iota it-length)))))))) |
|
501 |
- |
|
502 |
-#+nil |
|
503 |
-(defmacro <> (arity &rest funs) |
|
504 |
- (let ((arg-syms (loop repeat arity collect (gensym)))) |
|
505 |
- `(lambda (,@arg-syms) |
|
506 |
- (declare (dynamic-extent ,@arg-syms)) |
|
507 |
- ,(fw.lu:rollup-list (mapcar (lambda (x) |
|
508 |
- (etypecase x |
|
509 |
- (list `(funcall ,x)) |
|
510 |
- (symbol (list x)))) |
|
511 |
- funs) |
|
512 |
- arg-syms)))) |
|
513 |
- |
|
514 |
-(defmacro <>1 (&rest funs) |
|
515 |
- `(alexandria:compose ,@funs)) |