emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/taxy 247d473 01/10: Add/Change: taxy-take-keyed* -> tax


From: ELPA Syncer
Subject: [elpa] externals/taxy 247d473 01/10: Add/Change: taxy-take-keyed* -> taxy-take-keyed, key-fn chains
Date: Sun, 29 Aug 2021 04:57:19 -0400 (EDT)

branch: externals/taxy
commit 247d473607fec8f42c9d2ad3326865f22c51324b
Author: Adam Porter <adam@alphapapa.net>
Commit: Adam Porter <adam@alphapapa.net>

    Add/Change: taxy-take-keyed* -> taxy-take-keyed, key-fn chains
    
    taxy.el should now have met feature parity with bufler-group-tree.el,
    and also exceed it with the more flexible :take functions and other
    features.  It should now be a good foundation for these packages to
    build functionality on.
---
 README.org |  92 +++++++++++++++++++++++++++++----
 taxy.el    | 135 ++++++++++++++++++++++++++++++------------------
 taxy.info  | 172 +++++++++++++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 300 insertions(+), 99 deletions(-)

diff --git a/README.org b/README.org
index fa77774..2343d7a 100644
--- a/README.org
+++ b/README.org
@@ -288,7 +288,7 @@ And finally we'll define a taxy to organize them.  In this, 
we use a helper macr
        :taxys (list (make-taxy
                      :name "Sporty"
                      :take (lambda (object taxy)
-                             (taxy-take-keyed*
+                             (taxy-take-keyed
                               (list #'sport-venue
                                     (in 'ball 'sport-uses)
                                     (in 'disc 'sport-uses)
@@ -296,7 +296,7 @@ And finally we'll define a taxy to organize them.  In this, 
we use a helper macr
                                     (in 'racket 'sport-uses))
                               object taxy
                               ;; We set the `:then' function of the taxys
-                              ;; created by `taxy-take-keyed*' to `identity'
+                              ;; created by `taxy-take-keyed' to `identity'
                               ;; so they will not consume their objects.
                               :then #'identity)))))))
 #+END_SRC
@@ -345,7 +345,7 @@ That's pretty sporty.  But classifying them by venue first 
makes the racket and
        :taxys (list (make-taxy
                      :name "Sporty"
                      :take (lambda (object taxy)
-                             (taxy-take-keyed*
+                             (taxy-take-keyed
                               (list (in 'ball 'sport-uses)
                                     (in 'disc 'sport-uses)
                                     (in 'glove 'sport-uses)
@@ -392,7 +392,7 @@ That's better.  But I'd also like to see a very simple 
classification to help me
                (make-taxy
                 :name "Funny"
                 :take (lambda (object taxy)
-                        (taxy-take-keyed*
+                        (taxy-take-keyed
                          (list (lambda (sport)
                                  (if (sport-fun sport)
                                      'fun 'boring))
@@ -467,6 +467,7 @@ To return a taxy in a more human-readable format (with only 
relevant fields incl
 :END:
 :CONTENTS:
 - [[#multi-level-dynamic-taxys][Multi-level dynamic taxys]]
+- [[#chains-of-independent-multi-level-dynamic-taxys]["Chains" of independent, 
multi-level dynamic taxys]]
 :END:
 
 You may not always know in advance what taxonomy a set of objects fits into, 
so =taxy= lets you add taxys dynamically by using the ~:take~ function to add a 
taxy when an object is "taken into" a parent taxy.  For example, you could 
dynamically classify buffers by their major mode like so:
@@ -481,7 +482,7 @@ You may not always know in advance what taxonomy a set of 
objects fits into, so
      :taxys (list
              (make-taxy
               :name "Modes"
-              :take (apply-partially #'taxy-take-keyed 
#'buffery-major-mode)))))
+              :take (apply-partially #'taxy-take-keyed (list 
#'buffery-major-mode))))))
 
   ;; Note the use of `taxy-emptied' to avoid mutating the original taxy 
definition.
   (taxy-plain
@@ -489,7 +490,7 @@ You may not always know in advance what taxonomy a set of 
objects fits into, so
               (taxy-emptied buffery)))
 #+END_SRC
 
-The taxy's ~:take~ function is set to the ~taxy-take-keyed~ function, 
partially applied with the ~buffery-major-mode~ function as its ~key-fn~ 
(~taxy-fill~ supplies the buffer and the taxy as arguments), and it produces 
this taxonomy of buffers:
+The taxy's ~:take~ function is set to the ~taxy-take-keyed~ function, 
partially applied with the ~buffery-major-mode~ function as its list of 
~key-fns~ (~taxy-fill~ supplies the buffer and the taxy as arguments), and it 
produces this taxonomy of buffers:
 
 #+BEGIN_SRC elisp
   ("Buffers"
@@ -522,9 +523,9 @@ The taxy's ~:take~ function is set to the ~taxy-take-keyed~ 
function, partially
 
 *** Multi-level dynamic taxys
 
-Of course, the point of taxonomies is that they aren't restricted to a single 
level of depth, so you may also use the function ~taxy-take-keyed*~ (notice the 
~*~) to dynamically make multi-level taxys.  
+Of course, the point of taxonomies is that they aren't restricted to a single 
level of depth, so you may also use the function ~taxy-take-keyed~ to 
dynamically make multi-level taxys.
 
-Expanding on the previous example, we use ~cl-labels~ to define functions 
which are used in the taxy's definition, which are used in the ~:take~ 
function, which calls ~taxy-take-keyed*~ (rather than using ~apply-partially~ 
like in the previous example, we use a lambda function, which performs better 
than partially applied functions).  Then when the taxy is filled, a multi-level 
hierarchy is created dynamically, organizing buffers first by their directory, 
and then by mode in each directory.
+Expanding on the previous example, we use ~cl-labels~ to define functions 
which are used in the taxy's definition, which are used in the ~:take~ 
function, which calls ~taxy-take-keyed~ (rather than using ~apply-partially~ 
like in the previous example, we use a lambda function, which performs better 
than partially applied functions).  Then when the taxy is filled, a multi-level 
hierarchy is created dynamically, organizing buffers first by their directory, 
and then by mode in each directory.
 
 # MAYBE: A macro to define :take functions more concisely.
 
@@ -538,7 +539,7 @@ Expanding on the previous example, we use ~cl-labels~ to 
define functions which
                (make-taxy
                 :name "Directories"
                 :take (lambda (object taxy)
-                        (taxy-take-keyed* (list #'buffer-directory 
#'buffer-mode) object taxy)))))))
+                        (taxy-take-keyed (list #'buffer-directory 
#'buffer-mode) object taxy)))))))
 
   (taxy-plain
    (taxy-fill (buffer-list)
@@ -568,6 +569,72 @@ That produces a list like:
          (#<buffer taxy-magit-section.el> #<buffer taxy.el<taxy.el> #<buffer 
scratch.el>))))))))
 #+END_SRC
 
+*** "Chains" of independent, multi-level dynamic taxys
+:PROPERTIES:
+:ID:       8aec3671-ee22-44a0-968c-81443f4dcd74
+:END:
+
+/Naming things is hard./
+
+Going a step further, each element in the ~taxy-take-keyed~ function's 
~KEY-FNS~ argument may be a list of functions (or a list of lists of functions, 
etc.), which creates a "chain" of "independent" dynamic taxys.  Each such chain 
may be said to "short-circuit" the filling process in that, when an object is 
"taken" by the first key function in a chain, the object is not "offered" to 
other functions outside that chain.  This allows each dynamic sub-taxy to have 
its own set of sub-taxys, r [...]
+
+Building on the ~sporty~ example, let's define a taxy in which outdoor sports 
are classified only by whether they involve a disc, but indoor sports are 
additionally classified by whatever equipment they may use:
+
+#+BEGIN_SRC elisp :exports code :results silent :lexical t
+  (defvar sporty-dynamic
+    (cl-macrolet ((in (needle haystack)
+                      `(lambda (object)
+                         (when (member ,needle (funcall ,haystack object))
+                           ,needle))))
+      (cl-labels ((outdoor-p
+                   (sport) (when (eq 'outdoor (sport-venue sport))
+                             "Outdoor"))
+                  (indoor-p
+                   (sport) (when (eq 'indoor (sport-venue sport))
+                             "Indoor"))
+                  (disc-p
+                   (sport) (if (funcall (in 'disc 'sport-uses) sport)
+                               'disc
+                             'non-disc)))
+        (make-taxy
+         :name "Sporty (dynamic)"
+         :take (lambda (object taxy)
+                 (taxy-take-keyed
+                   (list (list #'outdoor-p #'disc-p)
+                         (list #'indoor-p
+                               (in 'ball 'sport-uses)
+                               (in 'disc 'sport-uses)
+                               (in 'glove 'sport-uses)
+                               (in 'racket 'sport-uses)))
+                   object taxy))))))
+#+END_SRC
+
+Now let's fill the taxy with the sports and format it:
+
+#+BEGIN_SRC elisp :exports code :results code
+  (thread-last sporty-dynamic
+    taxy-emptied
+    (taxy-fill sports)
+    (taxy-mapcar #'sport-name)
+    taxy-plain)
+#+END_SRC
+
+#+BEGIN_SRC elisp :exports code
+  ("Sporty (dynamic)"
+   (("Indoor"
+     ((ball
+       ("Volleyball" "Basketball")
+       ((glove
+         ("Handball"))
+        (racket
+         ("Racquetball"))))))
+    ("Outdoor"
+     ((disc
+       ("Ultimate" "Disc golf"))
+      (non-disc
+       ("Soccer" "Tennis" "Football" "Baseball"))))))
+#+END_SRC
+
 ** Reusable taxys
 
 Since taxys are structs, they may be stored in variables and used in other 
structs (being sure to copy the root taxy with ~taxy-emptied~ before filling).  
For example, this shows using =taxy= to classify Matrix rooms in 
[[https://github.com/alphapapa/ement.el][Ement.el]]:
@@ -717,10 +784,15 @@ Note that =taxy-magit-section.el= is not installed with 
the =taxy= package by de
 
 ** 0.2-pre
 
+*** Changes
+
++  Function ~taxy-take-keyed*~ is renamed to ~taxy-take-keyed~, replacing the 
old function: it's more powerful, and there's little reason to maintain two 
versions.
+
 *** Additions
 
-+  Struct ~taxy~ now has a ~:make~ slot, a function called to make new 
sub-taxys by ~take-take-keyed*~ (defaulting to ~make-taxy~).  This is useful 
when defining structs specialized on ~taxy~.
++  Struct ~taxy~ now has a ~:make~ slot, a function called to make new 
sub-taxys by ~take-take-keyed~ (defaulting to ~make-taxy~).  This is useful 
when defining structs specialized on ~taxy~.
 +  Struct ~taxy-magit-section~ now has an ~:indent~ slot, a number of 
characters by which to indent each level of sub-taxy, applied automatically by 
function ~taxy-magit-section-insert~.
++  Each element of the new ~taxy-take-keyed~'s ~KEY-FNS~ argument may now be a 
function or a list of functions (or a list of a list of functions, etc.).  
Lists of functions create "chains" of independent, dynamic taxys descending 
from a single root taxy.  See 
[[id:8aec3671-ee22-44a0-968c-81443f4dcd74][example]].
 
 *** Fixes
 
diff --git a/taxy.el b/taxy.el
index f39ec18..80e9013 100644
--- a/taxy.el
+++ b/taxy.el
@@ -134,61 +134,98 @@ Does not copy TAXY.  Destructively modifies TAXY, if FN 
does."
 
 (defalias 'taxy-mapc* #'taxy-mapc-taxys)
 
-(cl-defun taxy-take-keyed (key-fn object taxy &key (key-name-fn #'identity))
-  "Take OBJECT into TAXY, adding new taxys dynamically.
-Places OBJECT into a taxy in TAXY for the value returned by
-KEY-FN called with OBJECT.  The new taxy's name is that returned
-by KEY-NAME-FN called with OBJECT."
-  (let* ((key (funcall key-fn object))
-         (key-taxy
-          (or (cl-find-if (lambda (taxy-key)
-                            (equal key taxy-key))
-                          (taxy-taxys taxy)
-                          :key #'taxy-key)
-              (car
-               (push (make-taxy
-                      :name (funcall key-name-fn key) :key key
-                      :predicate (lambda (object)
-                                   (equal key (funcall key-fn object))))
-                     (taxy-taxys taxy))))))
-    (push object (taxy-objects key-taxy))))
-
-(cl-defun taxy-take-keyed*
+(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
 recursively as necessary.  Each new taxy's name is that returned
-by KEY-NAME-FN called with OBJECT."
-  (let ((key-fn (car key-fns)))
-    (if-let ((key (funcall key-fn object)))
-        (let ((key-taxy
-               (or (cl-find-if (lambda (taxy-key)
-                                 (equal key taxy-key))
-                               (taxy-taxys taxy)
-                               :key #'taxy-key)
-                   (car
-                    ;; Calling `make-taxy' directly might offer the compiler a 
chance to optimize
-                    ;; compared to using `funcall', but allowing taxy structs 
to specify their
-                    ;; own MAKE functions is very helpful when using 
specialized structs.
-                    (push (funcall (taxy-make taxy)
-                                   :name (funcall key-name-fn key)
-                                   :key key
-                                   :predicate (lambda (object)
-                                                (equal key (funcall key-fn 
object)))
-                                   :take (when (cdr key-fns)
-                                           (lambda (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)
-            (push object (taxy-objects key-taxy))))
-      ;; No key value: push to this taxy.
-      (if (cdr key-fns)
-          (taxy-take-keyed* (cdr key-fns) object taxy)
-        (push object (taxy-objects taxy))))))
+by KEY-NAME-FN called with OBJECT.
+
+Each element of KEY-FNS may be a function or a list of functions.
+A list of functions creates a \"chain\" of functions: when an
+object is matched by the first function in a chain, it is placed
+in that chain's taxonomy, and is not \"offered\" to functions
+outside of that chain.
+
+For example, if KEY-FNS were:
+
+  '(((lambda (n) (< n 10)) oddp)
+    ((lambda (n) (>= n 10)) evenp))
+
+Then a list of numbers from 0-19 would be classified
+like (listing numbers on a single line for the sake of example):
+
+  - <10:
+    - 0, 2, 4, 6, 8
+    - oddp:
+      - 1, 3, 5, 7, 9
+  - >=10:
+    - 11, 13, 15, 17, 19
+    - evenp:
+      - 10, 12, 14, 16, 18
+
+So only numbers below 10 are tested against `oddp', and only
+numbers greater-than-or-equal-to 10 are tested against
+`evenp'.  (A contrived example, of course, since testing against
+`evenp' or `oddp' is just the inverse.)"
+  (declare (indent defun))
+  (cl-macrolet ((offer-or-push
+                 () `(if (cdr key-fns)
+                         (taxy-take-keyed (cdr key-fns) object taxy
+                           :key-name-fn key-name-fn :then then)
+                       (push object (taxy-objects taxy)))))
+    (cl-typecase (car key-fns)
+      (function
+       ;; A single key function.
+       (let ((key-fn (car key-fns)))
+         (if-let ((key (funcall key-fn object)))
+             ;; This key function returned non-nil for the object:
+             ;; apply it to the appropriate sub-taxy.
+             (let ((key-taxy
+                    (or (cl-find-if (lambda (taxy-key)
+                                      (equal key taxy-key))
+                                    (taxy-taxys taxy)
+                                    :key #'taxy-key)
+                        ;; No existing, matching sub-taxy found: make
+                        ;; a new one and add it to TAXY's sub-taxys.
+                        (car
+                         (push (funcall
+                                ;; NOTE: Calling `make-taxy' directly might 
offer the
+                                ;; compiler a chance to optimize compared to 
using `funcall',
+                                ;; but allowing taxy structs to specify their 
own MAKE
+                                ;; functions is very helpful when using 
specialized structs.
+                                (taxy-make taxy)
+                                :name (funcall key-name-fn key)
+                                :key key
+                                :predicate (lambda (object)
+                                             (equal key (funcall key-fn 
object)))
+                                :take (when (cdr key-fns)
+                                        (lambda (object taxy)
+                                          (taxy-take-keyed (cdr key-fns) 
object taxy
+                                            :key-name-fn key-name-fn :then 
then)))
+                                :then then)
+                               (taxy-taxys taxy))))))
+               (if (cdr key-fns)
+                   ;; Other key-fns remain: offer object to them, allowing
+                   ;; them to create more sub-taxys beneath this key-taxy.
+                   (taxy-take-keyed (cdr key-fns) object key-taxy
+                     :key-name-fn key-name-fn :then then)
+                 ;; No more key-fns remain: add object to this taxy.
+                 (push object (taxy-objects key-taxy))))
+           ;; No key value: offer to other KEY-FNS or push to this taxy.
+           (offer-or-push))))
+      (list
+       ;; A "chain" of key functions.
+       (or (when (funcall (caar key-fns) object)
+             ;; The first function in this chain returns non-nil for
+             ;; the object: apply the object to the chain.
+             (taxy-take-keyed (car key-fns) object taxy
+               :key-name-fn key-name-fn :then then))
+           ;; This "chain" of key-fns didn't take the object: offer it to
+           ;; other chains, or push to this taxy if they don't take it.
+           (offer-or-push))))))
 
 (defun taxy-size (taxy)
   "Return the number of objects TAXY holds.
diff --git a/taxy.info b/taxy.info
index e255d51..17ffe88 100644
--- a/taxy.info
+++ b/taxy.info
@@ -44,6 +44,7 @@ Usage
 Dynamic taxys
 
 * Multi-level dynamic taxys::
+* "Chains" of independent, multi-level dynamic taxys: "Chains" of independent 
multi-level dynamic taxys. 
 
 Changelog
 
@@ -52,6 +53,7 @@ Changelog
 
 0.2-pre
 
+* Changes::
 * Additions::
 * Fixes::
 
@@ -323,7 +325,7 @@ key functions:
           :taxys (list (make-taxy
                         :name "Sporty"
                         :take (lambda (object taxy)
-                                (taxy-take-keyed*
+                                (taxy-take-keyed
                                  (list #'sport-venue
                                        (in 'ball 'sport-uses)
                                        (in 'disc 'sport-uses)
@@ -331,7 +333,7 @@ key functions:
                                        (in 'racket 'sport-uses))
                                  object taxy
                                  ;; We set the `:then' function of the taxys
-                                 ;; created by `taxy-take-keyed*' to `identity'
+                                 ;; created by `taxy-take-keyed' to `identity'
                                  ;; so they will not consume their objects.
                                  :then #'identity)))))))
 
@@ -375,7 +377,7 @@ racket and glove sports not be listed together.  Let’s swap 
that around:
           :taxys (list (make-taxy
                         :name "Sporty"
                         :take (lambda (object taxy)
-                                (taxy-take-keyed*
+                                (taxy-take-keyed
                                  (list (in 'ball 'sport-uses)
                                        (in 'disc 'sport-uses)
                                        (in 'glove 'sport-uses)
@@ -419,7 +421,7 @@ to help me decide what to play:
                   (make-taxy
                    :name "Funny"
                    :take (lambda (object taxy)
-                           (taxy-take-keyed*
+                           (taxy-take-keyed
                             (list (lambda (sport)
                                     (if (sport-fun sport)
                                         'fun 'boring))
@@ -521,7 +523,7 @@ File: README.info,  Node: Dynamic taxys,  Next: Reusable 
taxys,  Up: Usage
 3.1 Dynamic taxys
 =================
 
-   • 
+   • • 
    You may not always know in advance what taxonomy a set of objects
 fits into, so taxy lets you add taxys dynamically by using the ‘:take’
 function to add a taxy when an object is "taken into" a parent taxy.
@@ -537,7 +539,7 @@ like so:
         :taxys (list
                 (make-taxy
                  :name "Modes"
-                 :take (apply-partially #'taxy-take-keyed 
#'buffery-major-mode)))))
+                 :take (apply-partially #'taxy-take-keyed (list 
#'buffery-major-mode))))))
 
      ;; Note the use of `taxy-emptied' to avoid mutating the original taxy 
definition.
      (taxy-plain
@@ -545,9 +547,9 @@ like so:
                  (taxy-emptied buffery)))
 
    The taxy’s ‘:take’ function is set to the ‘taxy-take-keyed’ function,
-partially applied with the ‘buffery-major-mode’ function as its ‘key-fn’
-(‘taxy-fill’ supplies the buffer and the taxy as arguments), and it
-produces this taxonomy of buffers:
+partially applied with the ‘buffery-major-mode’ function as its list of
+‘key-fns’ (‘taxy-fill’ supplies the buffer and the taxy as arguments),
+and it produces this taxonomy of buffers:
 
      ("Buffers"
       (("Modes"
@@ -579,21 +581,21 @@ produces this taxonomy of buffers:
 * Menu:
 
 * Multi-level dynamic taxys::
+* "Chains" of independent, multi-level dynamic taxys: "Chains" of independent 
multi-level dynamic taxys. 
 
 
-File: README.info,  Node: Multi-level dynamic taxys,  Up: Dynamic taxys
+File: README.info,  Node: Multi-level dynamic taxys,  Next: "Chains" of 
independent multi-level dynamic taxys,  Up: Dynamic taxys
 
 3.1.1 Multi-level dynamic taxys
 -------------------------------
 
 Of course, the point of taxonomies is that they aren’t restricted to a
 single level of depth, so you may also use the function
-‘taxy-take-keyed*’ (notice the ‘*’) to dynamically make multi-level
-taxys.
+‘taxy-take-keyed’ to dynamically make multi-level taxys.
 
    Expanding on the previous example, we use ‘cl-labels’ to define
 functions which are used in the taxy’s definition, which are used in the
-‘:take’ function, which calls ‘taxy-take-keyed*’ (rather than using
+‘:take’ function, which calls ‘taxy-take-keyed’ (rather than using
 ‘apply-partially’ like in the previous example, we use a lambda
 function, which performs better than partially applied functions).  Then
 when the taxy is filled, a multi-level hierarchy is created dynamically,
@@ -609,7 +611,7 @@ directory.
                   (make-taxy
                    :name "Directories"
                    :take (lambda (object taxy)
-                           (taxy-take-keyed* (list #'buffer-directory 
#'buffer-mode) object taxy)))))))
+                           (taxy-take-keyed (list #'buffer-directory 
#'buffer-mode) object taxy)))))))
 
      (taxy-plain
       (taxy-fill (buffer-list)
@@ -637,6 +639,78 @@ directory.
             (#<buffer taxy-magit-section.el> #<buffer taxy.el<taxy.el> 
#<buffer scratch.el>))))))))
 
 
+File: README.info,  Node: "Chains" of independent multi-level dynamic taxys,  
Prev: Multi-level dynamic taxys,  Up: Dynamic taxys
+
+3.1.2 "Chains" of independent, multi-level dynamic taxys
+--------------------------------------------------------
+
+_Naming things is hard._
+
+   Going a step further, each element in the ‘taxy-take-keyed’
+function’s ‘KEY-FNS’ argument may be a list of functions (or a list of
+lists of functions, etc.), which creates a "chain" of "independent"
+dynamic taxys.  Each such chain may be said to "short-circuit" the
+filling process in that, when an object is "taken" by the first key
+function in a chain, the object is not "offered" to other functions
+outside that chain.  This allows each dynamic sub-taxy to have its own
+set of sub-taxys, rather than sharing the same "global" set.  In effect,
+this creates multiple, unique taxonomies that share a single root taxy.
+
+   Building on the ‘sporty’ example, let’s define a taxy in which
+outdoor sports are classified only by whether they involve a disc, but
+indoor sports are additionally classified by whatever equipment they may
+use:
+
+     (defvar sporty-dynamic
+       (cl-macrolet ((in (needle haystack)
+                         `(lambda (object)
+                            (when (member ,needle (funcall ,haystack object))
+                              ,needle))))
+         (cl-labels ((outdoor-p
+                      (sport) (when (eq 'outdoor (sport-venue sport))
+                                "Outdoor"))
+                     (indoor-p
+                      (sport) (when (eq 'indoor (sport-venue sport))
+                                "Indoor"))
+                     (disc-p
+                      (sport) (if (funcall (in 'disc 'sport-uses) sport)
+                                  'disc
+                                'non-disc)))
+           (make-taxy
+            :name "Sporty (dynamic)"
+            :take (lambda (object taxy)
+                    (taxy-take-keyed
+                      (list (list #'outdoor-p #'disc-p)
+                            (list #'indoor-p
+                                  (in 'ball 'sport-uses)
+                                  (in 'disc 'sport-uses)
+                                  (in 'glove 'sport-uses)
+                                  (in 'racket 'sport-uses)))
+                      object taxy))))))
+
+   Now let’s fill the taxy with the sports and format it:
+
+     (thread-last sporty-dynamic
+       taxy-emptied
+       (taxy-fill sports)
+       (taxy-mapcar #'sport-name)
+       taxy-plain)
+
+     ("Sporty (dynamic)"
+      (("Indoor"
+        ((ball
+          ("Volleyball" "Basketball")
+          ((glove
+            ("Handball"))
+           (racket
+            ("Racquetball"))))))
+       ("Outdoor"
+        ((disc
+          ("Ultimate" "Disc golf"))
+         (non-disc
+          ("Soccer" "Tennis" "Football" "Baseball"))))))
+
+
 File: README.info,  Node: Reusable taxys,  Next: Threading macros,  Prev: 
Dynamic taxys,  Up: Usage
 
 3.2 Reusable taxys
@@ -815,26 +889,42 @@ File: README.info,  Node: 02-pre,  Next: 01,  Up: 
Changelog
 
 * Menu:
 
+* Changes::
 * Additions::
 * Fixes::
 
 
-File: README.info,  Node: Additions,  Next: Fixes,  Up: 02-pre
+File: README.info,  Node: Changes,  Next: Additions,  Up: 02-pre
+
+4.1.1 Changes
+-------------
+
+   • Function ‘taxy-take-keyed*’ is renamed to ‘taxy-take-keyed’,
+     replacing the old function: it’s more powerful, and there’s little
+     reason to maintain two versions.
+
+
+File: README.info,  Node: Additions,  Next: Fixes,  Prev: Changes,  Up: 02-pre
 
-4.1.1 Additions
+4.1.2 Additions
 ---------------
 
    • Struct ‘taxy’ now has a ‘:make’ slot, a function called to make new
-     sub-taxys by ‘take-take-keyed*’ (defaulting to ‘make-taxy’).  This
+     sub-taxys by ‘take-take-keyed’ (defaulting to ‘make-taxy’).  This
      is useful when defining structs specialized on ‘taxy’.
    • Struct ‘taxy-magit-section’ now has an ‘:indent’ slot, a number of
      characters by which to indent each level of sub-taxy, applied
      automatically by function ‘taxy-magit-section-insert’.
+   • Each element of the new ‘taxy-take-keyed’’s ‘KEY-FNS’ argument may
+     now be a function or a list of functions (or a list of a list of
+     functions, etc.).  Lists of functions create "chains" of
+     independent, dynamic taxys descending from a single root taxy.  See
+     *note example: "Chains" of independent multi-level dynamic taxys.
 
 
 File: README.info,  Node: Fixes,  Prev: Additions,  Up: 02-pre
 
-4.1.2 Fixes
+4.1.3 Fixes
 -----------
 
    • ‘taxy-magit-section’’s ‘insert-object’ function.
@@ -896,28 +986,30 @@ GPLv3
 
 Tag Table:
 Node: Top218
-Node: Examples1379
-Node: Numbery (starting basically)1698
-Node: Lettery (filling incrementally)7457
-Node: Sporty (understanding completely)9906
-Node: Applications16385
-Node: Installation16785
-Node: Usage17086
-Node: Dynamic taxys19207
-Node: Multi-level dynamic taxys21625
-Node: Reusable taxys23788
-Node: Threading macros27957
-Node: Modifying filled taxys28496
-Node: Magit section29589
-Node: Changelog30190
-Node: 02-pre30340
-Node: Additions30462
-Node: Fixes31002
-Node: 0131252
-Node: Development31355
-Node: Copyright assignment31561
-Node: Credits32160
-Node: License32350
+Node: Examples1497
+Node: Numbery (starting basically)1816
+Node: Lettery (filling incrementally)7575
+Node: Sporty (understanding completely)10024
+Node: Applications16499
+Node: Installation16899
+Node: Usage17200
+Node: Dynamic taxys19321
+Node: Multi-level dynamic taxys21865
+Node: "Chains" of independent multi-level dynamic taxys24062
+Node: Reusable taxys26942
+Node: Threading macros31111
+Node: Modifying filled taxys31650
+Node: Magit section32743
+Node: Changelog33344
+Node: 02-pre33494
+Node: Changes33628
+Node: Additions33916
+Node: Fixes34831
+Node: 0135081
+Node: Development35184
+Node: Copyright assignment35390
+Node: Credits35989
+Node: License36179
 
 End Tag Table
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]