diff --git a/List-of-Macros.md b/List-of-Macros.md index 4a64096..a9753e1 100644 --- a/List-of-Macros.md +++ b/List-of-Macros.md @@ -19,12 +19,138 @@ Declares a new symbol available to be defined as a path. If the path will requir (0 0 2 3 4) ``` +### defpathedfn + +`(defpathedfn name & args)` + +This is sugar to add [:pathedfn true] to the metadata map of the function. The syntax is the same as `defn` (optional docstring, etc.). Often used with [fixed-pathed-nav](#fixed-pathed-nav) or [variable-pathed-nav](#variable-pathed-nav) to enable late binding parameters. Non-path arguments should be preceded by ^:notpath. + +```clojure +=> (defpathedfn walk-pred + "Walks to integers satisfying apred." + [^:notpath apred] + (walker #(and (integer? %) (apred %)))) +=> (select (walk-pred even?) [1 [2] [[[3 4]]] [5 [[6]] 7 8]]) +(2 4 6 8) +=> (transform (walk-pred even?) #(/ % 2) [1 2 [3] [[[4]]] [5 6] [[7 8]]]) +[1 1 [3] [[[2]]] [5 3] [[7 4]]] + + +;; The implementation of transformed +(defpathedfn transformed + "Navigates to a view of the current value by transforming it with the + specified path and update-fn. + The input path may be parameterized, in which case the result of transformed + will be parameterized in the order of which the parameterized navigators + were declared." + [path ^:notpath update-fn] + ;; Bind the passed in path to late + ;; Returns a navigator with the given select* and transform* implementations + (fixed-pathed-nav [late path] + (select* [this structure next-fn] + (next-fn (compiled-transform late update-fn structure))) + (transform* [this structure next-fn] + (next-fn (compiled-transform late update-fn structure))))) +``` + +### defprotocolpath + +`(defprotocolpath name)` + +`(defprotocolpath name params)` + +Defines a navigator that chooses the path to take based on the type +of the value at the current point. May be specified with parameters to +specify that all extensions must require that number of parameters. + +Currently not available for ClojureScript. + +```clojure +=> (defrecord SingleAccount [funds]) +=> (defrecord FamilyAccount [single-accounts]) + +=> (defprotocolpath FundsPath) +=> (extend-protocolpath FundsPath + SingleAccount :funds + FamilyAccount [:single-accounts ALL FundsPath]) +=> (select [ALL FundsPath] + [(->SingleAccount 100) (->SingleAccount 3) + (->FamilyAccount [(->SingleAccount 15) (->SingleAccount 12)])]) +[100 3 15 12] +``` + +### extend-protocolpath + +`(extend-protocolpath protpath & extensions)` + +Extends a protocol path `protpath` to a list of types. The `extensions` argument has the form `type1 path1 type2 path2...`. + +See [defprotocolpath](#defprotocolpath) for an example. + +### fixed-pathed-nav + +`(fixed-pathed-nav bindings select-impl transform-impl)` + +`(fixed-pathed-nav bindings transform-impl select-impl)` + +The first form is canonical. + +This helper is used to define navigators that take in a fixed number of other +paths as input. Those paths may require late-bound params, so this helper +will create a parameterized navigator if that is the case. If no late-bound params +are required, then the result is executable. + +`bindings` must be of the form `[path-binding1 path1 path-binding2 path2...]`. + +`select-impl` must be of the form `(select* [this structure next-fn] body)`. It should return the result of calling `next-fn` on whatever transformation the navigator applies to `structure`. + +`transform-impl` must be of the form `(transform* [this structure next-fn] body)`. It should find the result of calling `nextfn` on whatever transformation the navigator applies to `structure`. Then it should return the result of reconstructing the original structure using the results of the `nextfn` call. + +See [defpathedfn](#defpathedfn) for an example. + ### providepath `(providepath name apath)` Defines the path that will be associated to the provided name. The name must have been previously declared using [declarepath](#declarepath). +### variable-pathed-nav + +`(variable-pathed-nav [paths-binding paths-seq] select-impl transform-impl)` + +`(variable-pathed-nav [paths-binding paths-seq] transform-impl select-impl)` + +The first form is canonical. + +This helper is used to define navigators that take in a variable number of other +paths as input. Those paths may require late-bound params, so this helper +will create a parameterized navigator if that is the case. If no late-bound params +are required, then the result is executable. + +Binds the passed in seq of paths to `paths-binding`, which can be used in `select-impl` and `transform-impl`. + +The implementation of `multi-path` is a nice example of the use of `variable-pathed-nav`. + +```clojure +=> (defpathedfn multi-path + [& paths] + (variable-pathed-nav [compiled-paths paths] + (select* [this structure next-fn] + (->> compiled-paths + ;; seq with the results of navigating each passed in path + (mapcat #(compiled-select % structure)) + ;; pass each result to the following navigator + (mapcat next-fn) + doall)) + (transform* [this structure next-fn] + ;; apply the transform to each passed in path in order + (reduce + (fn [structure path] + (compiled-transform path next-fn structure)) + structure + compiled-paths)))) +``` + ## Collector Macros ### defcollector @@ -47,6 +173,41 @@ An informative example is the actual implementation of `putval`, which follows. (3 4 5 6 7) ``` +### paramscollector + +`(paramscollector params collect-val-impl)` + +Defines a Collector with late bound parameters. This collector can be precompiled +with other selectors without knowing the parameters. When precompiled with other +selectors, the resulting selector takes in parameters for all selectors in the path +that needed parameters (in the order in which they were declared). + +Returns an "anonymous Collector." See [defcollector](#defcollector). + +### pathed-collector + +`(pathed-collector [name path] collect-val-impl)` + +This helper is used to define collectors that take in a single selector +paths as input. That path may require late-bound params, so this helper +will create a parameterized selector if that is the case. If no late-bound params +are required, then the result is executable. + +Binds the passed in path to `name`. + +`collect-val-impl` must be of the form `(collect-val [this structure] body)`. It should return the value to be collected. + +The implementation of `collect` is a good example of how `pathed-collector` can be used. + +```clojure +=> (defpathedfn + collect + [& path] + (pathed-collector [late path] + (collect-val [this structure] + (compiled-select late structure)))) +``` + ## Navigator Macros ### defnav @@ -94,3 +255,15 @@ See also [nav](#nav) `(nav params transform-impl select-impl)` Returns an "anonymous navigator." See [defnav](#defnav). + +### paramsfn + +`(paramsfn params [structure-binding] impl)` + +Helper macro for defining filter functions with late binding parameters. + +```clojure +=> (let [c-path (comp-paths (paramsfn [val] [x] (< x val)))] + (select [ALL (c-path 5)] [2 7 3 4 10 8])) +[2 3 4] +```