branch: externals/taxy commit 2c044ed4b2033a36878b3ed00cdc2afb73f32368 Author: Adam Porter <a...@alphapapa.net> Commit: Adam Porter <a...@alphapapa.net>
Add: (taxy-take-keyed*) :then, and examples --- README.org | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++- taxy.el | 7 +- taxy.info | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 455 insertions(+), 24 deletions(-) diff --git a/README.org b/README.org index 94f5c24..da4b5b4 100644 --- a/README.org +++ b/README.org @@ -23,7 +23,10 @@ Helpful features include: :END: :CONTENTS: - [[#examples][Examples]] - - [[#example-applications][Example applications]] + - [[#numbery-starting-basically][Numbery (starting basically)]] + - [[#lettery-filling-incrementally][Lettery (filling incrementally)]] + - [[#sporty-understanding-completely][Sporty (understanding completely)]] + - [[#applications][Applications]] - [[#usage][Usage]] - [[#dynamic-taxys][Dynamic taxys]] - [[#reusable-taxys][Reusable taxys]] @@ -35,6 +38,19 @@ Helpful features include: :END: * Examples +:PROPERTIES: +:TOC: :include descendants :depth 1 +:END: +:CONTENTS: +- [[#numbery-starting-basically][Numbery (starting basically)]] +- [[#lettery-filling-incrementally][Lettery (filling incrementally)]] +- [[#sporty-understanding-completely][Sporty (understanding completely)]] +- [[#applications][Applications]] +:END: + +May these examples help you classify your understanding. + +** Numbery (starting basically) Let's imagine a silly taxonomy of numbers below 100: @@ -134,6 +150,8 @@ You might think about how to produce that by writing some imperative code, but = The ~taxy-fill~ function applies the numbers in a "cascade" down the hierarchy of "taxys", and the ~taxy-plain~ function returns a meaningful subset of the taxys' slots, suitable for display. +** Lettery (filling incrementally) + You can also add more objects after the hierarchy has been filled: #+BEGIN_SRC elisp @@ -200,7 +218,204 @@ That's better: ("B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" "N" "P" "Q" "R" "S" "T" "V" "W" "X" "Y" "Z")))) #+END_SRC -** Example applications +** Sporty (understanding completely) + +Let's try to understand a few things about sports. First we'll define a struct to make them easier to grasp: + +#+BEGIN_SRC elisp :exports code :results silent + (cl-defstruct sport + name uses venue fun) +#+END_SRC + +Now we'll make a list of sports: + +#+BEGIN_SRC elisp :exports code :results silent + (defvar sports + (list (make-sport :name "Baseball" + :uses '(bat ball glove) + :venue 'outdoor + :fun t) + (make-sport :name "Football" + :uses '(ball) + :venue 'outdoor + :fun t) + (make-sport :name "Basketball" + :uses '(ball hoop) + :venue 'indoor + :fun t) + (make-sport :name "Tennis" + :uses '(ball racket) + :venue 'outdoor + :fun t) + (make-sport :name "Racquetball" + :uses '(ball racket) + :venue 'indoor + :fun t) + (make-sport :name "Handball" + :uses '(ball glove) + :venue 'indoor + :fun t) + (make-sport :name "Soccer" + :uses '(ball) + :venue 'outdoor + :fun nil) + (make-sport :name "Disc golf" + :uses '(disc basket) + :venue 'outdoor + :fun t) + (make-sport :name "Ultimate" + :uses '(disc) + :venue 'outdoor + :fun t) + (make-sport :name "Volleyball" + :uses '(ball) + :venue 'indoor + :fun t))) +#+END_SRC + +And finally we'll define a taxy to organize them. In this, we use a helper macro to make the ~member~ function easier to use in the list of key functions: + +#+BEGIN_SRC elisp :exports code :results silent :lexical t + (defvar sporty + (cl-macrolet ((in (needle haystack) + `(lambda (object) + (when (member ,needle (funcall ,haystack object)) + ,needle)))) + (make-taxy + :taxys (list (make-taxy + :name "Sporty" + :take (lambda (object taxy) + (taxy-take-keyed* + (list #'sport-venue + (in 'ball 'sport-uses) + (in 'disc 'sport-uses) + (in 'glove 'sport-uses) + (in 'racket 'sport-uses)) + object taxy + ;; We set the `:then' function of the taxys + ;; created by `taxy-take-keyed*' to `identity' + ;; so they will not consume their objects. + :then #'identity))))))) +#+END_SRC + +Now let's fill the taxy with the sports and format it: + +#+BEGIN_SRC elisp :exports code + (thread-last sporty + taxy-emptied + (taxy-fill sports) + (taxy-mapcar #'sport-name) + taxy-plain) +#+END_SRC + +#+BEGIN_SRC elisp :exports code +((("Sporty" + ((disc + ((outdoor + ("Ultimate" "Disc golf")))) + (ball + ((racket + ((indoor + ("Racquetball")) + (outdoor + ("Tennis")))) + (indoor + ("Volleyball" "Basketball")) + (outdoor + ("Soccer" "Football")) + (glove + ((indoor + ("Handball")) + (outdoor + ("Baseball")))))))))) +#+END_SRC + +That's pretty sporty. But classifying them by venue first makes the racket and glove sports not be listed together. Let's swap that around: + +#+BEGIN_SRC elisp :exports code :results silent + (defvar sporty + (cl-macrolet ((in (needle haystack) + `(lambda (object) + (when (member ,needle (funcall ,haystack object)) + ,needle)))) + (make-taxy + :taxys (list (make-taxy + :name "Sporty" + :take (lambda (object taxy) + (taxy-take-keyed* + (list (in 'ball 'sport-uses) + (in 'disc 'sport-uses) + (in 'glove 'sport-uses) + (in 'racket 'sport-uses) + #'sport-venue) + object taxy + :then #'identity))))))) + + (thread-last sporty + taxy-emptied + (taxy-fill sports) + (taxy-mapcar #'sport-name) + taxy-plain) +#+END_SRC + +#+BEGIN_SRC elisp :exports code +((("Sporty" + ((disc + ((outdoor + ("Ultimate" "Disc golf")))) + (ball + ((racket + ((indoor + ("Racquetball")) + (outdoor + ("Tennis")))) + (indoor + ("Volleyball" "Basketball")) + (outdoor + ("Soccer" "Football")) + (glove + ((indoor + ("Handball")) + (outdoor + ("Baseball")))))))))) +#+END_SRC + +That's better. But I'd also like to see a very simple classification to help me decide what to play: + +#+BEGIN_SRC elisp :exports code + (thread-last + (make-taxy + :taxys (list + (make-taxy + :name "Funny" + :take (lambda (object taxy) + (taxy-take-keyed* + (list (lambda (sport) + (if (sport-fun sport) + 'fun 'boring)) + #'sport-venue) + object taxy))))) + taxy-emptied + (taxy-fill sports) + (taxy-mapcar #'sport-name) + taxy-plain) +#+END_SRC + +#+BEGIN_SRC elisp :exports code +((("Funny" + ((boring + ((outdoor + ("Soccer")))) + (fun + ((indoor + ("Volleyball" "Handball" "Racquetball" "Basketball")) + (outdoor + ("Ultimate" "Disc golf" "Tennis" "Football" "Baseball")))))))) +#+END_SRC + +Ah, now I understand. + +** Applications Some example applications may be found in the [[file:examples/README.org][examples directory]]: diff --git a/taxy.el b/taxy.el index 334d1c8..0697aae 100644 --- a/taxy.el +++ b/taxy.el @@ -146,7 +146,9 @@ by KEY-NAME-FN called with OBJECT." (taxy-taxys taxy)))))) (push object (taxy-objects key-taxy)))) -(cl-defun taxy-take-keyed* (key-fns object taxy &key (key-name-fn #'identity)) +(cl-defun taxy-take-keyed* + (key-fns object taxy + &key (key-name-fn #'identity) (then #'ignore)) "Take OBJECT into TAXY, adding new taxys dynamically and recursively. Places OBJECT into a taxy in TAXY for the value returned by KEY-FNS called with OBJECT. The new taxys are added to TAXY @@ -165,7 +167,8 @@ by KEY-NAME-FN called with OBJECT." (equal key (funcall key-fn object))) :take (when (cdr key-fns) (lambda (object taxy) - (taxy-take-keyed* (cdr key-fns) object taxy)))) + (taxy-take-keyed* (cdr key-fns) object taxy))) + :then then) (taxy-taxys taxy)))))) (if (cdr key-fns) (taxy-take-keyed* (cdr key-fns) object key-taxy) diff --git a/taxy.info b/taxy.info index c8e4df4..418868f 100644 --- a/taxy.info +++ b/taxy.info @@ -23,7 +23,11 @@ taxy.el Examples -* Example applications:: +* Numbery (starting basically):: +* Lettery (filling incrementally):: +* Sporty (understanding completely):: +* Applications:: + Usage @@ -63,6 +67,22 @@ File: README.info, Node: Examples, Next: Usage, Prev: Top, Up: Top 1 Examples ********** + • • • • + May these examples help you classify your understanding. + +* Menu: + +* Numbery (starting basically):: +* Lettery (filling incrementally):: +* Sporty (understanding completely):: +* Applications:: + + +File: README.info, Node: Numbery (starting basically), Next: Lettery (filling incrementally), Up: Examples + +1.1 Numbery (starting basically) +================================ + Let’s imagine a silly taxonomy of numbers below 100: ("Numbery" "A silly taxonomy of numbers." @@ -161,7 +181,13 @@ manner: hierarchy of "taxys", and the ‘taxy-plain’ function returns a meaningful subset of the taxys’ slots, suitable for display. - You can also add more objects after the hierarchy has been filled: + +File: README.info, Node: Lettery (filling incrementally), Next: Sporty (understanding completely), Prev: Numbery (starting basically), Up: Examples + +1.2 Lettery (filling incrementally) +=================================== + +You can also add more objects after the hierarchy has been filled: (defvar lettery (make-taxy :name "Lettery" @@ -215,15 +241,199 @@ subset of the taxys’ slots, suitable for display. ("Consonants" "Well, if they aren't a vowel..." ("B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" "N" "P" "Q" "R" "S" "T" "V" "W" "X" "Y" "Z")))) -* Menu: + +File: README.info, Node: Sporty (understanding completely), Next: Applications, Prev: Lettery (filling incrementally), Up: Examples + +1.3 Sporty (understanding completely) +===================================== + +Let’s try to understand a few things about sports. First we’ll define a +struct to make them easier to grasp: + + (cl-defstruct sport + name uses venue fun) + + Now we’ll make a list of sports: + + (defvar sports + (list (make-sport :name "Baseball" + :uses '(bat ball glove) + :venue 'outdoor + :fun t) + (make-sport :name "Football" + :uses '(ball) + :venue 'outdoor + :fun t) + (make-sport :name "Basketball" + :uses '(ball hoop) + :venue 'indoor + :fun t) + (make-sport :name "Tennis" + :uses '(ball racket) + :venue 'outdoor + :fun t) + (make-sport :name "Racquetball" + :uses '(ball racket) + :venue 'indoor + :fun t) + (make-sport :name "Handball" + :uses '(ball glove) + :venue 'indoor + :fun t) + (make-sport :name "Soccer" + :uses '(ball) + :venue 'outdoor + :fun nil) + (make-sport :name "Disc golf" + :uses '(disc basket) + :venue 'outdoor + :fun t) + (make-sport :name "Ultimate" + :uses '(disc) + :venue 'outdoor + :fun t) + (make-sport :name "Volleyball" + :uses '(ball) + :venue 'indoor + :fun t))) + + And finally we’ll define a taxy to organize them. In this, we use a +helper macro to make the ‘member’ function easier to use in the list of +key functions: + + (defvar sporty + (cl-macrolet ((in (needle haystack) + `(lambda (object) + (when (member ,needle (funcall ,haystack object)) + ,needle)))) + (make-taxy + :taxys (list (make-taxy + :name "Sporty" + :take (lambda (object taxy) + (taxy-take-keyed* + (list #'sport-venue + (in 'ball 'sport-uses) + (in 'disc 'sport-uses) + (in 'glove 'sport-uses) + (in 'racket 'sport-uses)) + object taxy + ;; We set the `:then' function of the taxys + ;; created by `taxy-take-keyed*' to `identity' + ;; so they will not consume their objects. + :then #'identity))))))) + + Now let’s fill the taxy with the sports and format it: + + (thread-last sporty + taxy-emptied + (taxy-fill sports) + (taxy-mapcar #'sport-name) + taxy-plain) + + ((("Sporty" + ((disc + ((outdoor + ("Ultimate" "Disc golf")))) + (ball + ((racket + ((indoor + ("Racquetball")) + (outdoor + ("Tennis")))) + (indoor + ("Volleyball" "Basketball")) + (outdoor + ("Soccer" "Football")) + (glove + ((indoor + ("Handball")) + (outdoor + ("Baseball")))))))))) + + That’s pretty sporty. But classifying them by venue first makes the +racket and glove sports not be listed together. Let’s swap that around: + + (defvar sporty + (cl-macrolet ((in (needle haystack) + `(lambda (object) + (when (member ,needle (funcall ,haystack object)) + ,needle)))) + (make-taxy + :taxys (list (make-taxy + :name "Sporty" + :take (lambda (object taxy) + (taxy-take-keyed* + (list (in 'ball 'sport-uses) + (in 'disc 'sport-uses) + (in 'glove 'sport-uses) + (in 'racket 'sport-uses) + #'sport-venue) + object taxy + :then #'identity))))))) + + (thread-last sporty + taxy-emptied + (taxy-fill sports) + (taxy-mapcar #'sport-name) + taxy-plain) + + ((("Sporty" + ((disc + ((outdoor + ("Ultimate" "Disc golf")))) + (ball + ((racket + ((indoor + ("Racquetball")) + (outdoor + ("Tennis")))) + (indoor + ("Volleyball" "Basketball")) + (outdoor + ("Soccer" "Football")) + (glove + ((indoor + ("Handball")) + (outdoor + ("Baseball")))))))))) + + That’s better. But I’d also like to see a very simple classification +to help me decide what to play: + + (thread-last + (make-taxy + :taxys (list + (make-taxy + :name "Funny" + :take (lambda (object taxy) + (taxy-take-keyed* + (list (lambda (sport) + (if (sport-fun sport) + 'fun 'boring)) + #'sport-venue) + object taxy))))) + taxy-emptied + (taxy-fill sports) + (taxy-mapcar #'sport-name) + taxy-plain) + + ((("Funny" + ((boring + ((outdoor + ("Soccer")))) + (fun + ((indoor + ("Volleyball" "Handball" "Racquetball" "Basketball")) + (outdoor + ("Ultimate" "Disc golf" "Tennis" "Football" "Baseball")))))))) -* Example applications:: + Ah, now I understand. -File: README.info, Node: Example applications, Up: Examples +File: README.info, Node: Applications, Prev: Sporty (understanding completely), Up: Examples -1.1 Example applications -======================== +1.4 Applications +================ Some example applications may be found in the examples directory (examples/README.org): @@ -601,19 +811,22 @@ GPLv3 Tag Table: Node: Top218 -Node: Examples1164 -Node: Example applications9099 -Node: Usage9481 -Node: Dynamic taxys11598 -Node: Multi-level dynamic taxys14016 -Node: Reusable taxys16179 -Node: Threading macros20348 -Node: Modifying filled taxys20887 -Node: Magit section21980 -Node: Changelog22581 -Node: 01-pre22719 -Node: Development22813 -Node: License22984 +Node: Examples1264 +Node: Numbery (starting basically)1576 +Node: Lettery (filling incrementally)7335 +Node: Sporty (understanding completely)9784 +Node: Applications16263 +Node: Usage16663 +Node: Dynamic taxys18780 +Node: Multi-level dynamic taxys21198 +Node: Reusable taxys23361 +Node: Threading macros27530 +Node: Modifying filled taxys28069 +Node: Magit section29162 +Node: Changelog29763 +Node: 01-pre29901 +Node: Development29995 +Node: License30166 End Tag Table