Updated List of Macros (markdown)
This commit is contained in:
parent
0a1db694cf
commit
364e9cd54f
1 changed files with 2 additions and 225 deletions
|
|
@ -16,22 +16,15 @@
|
|||
- [traverse](#traverse)
|
||||
- [Path Macros](#path-macros)
|
||||
- [declarepath](#declarepath)
|
||||
- [defpathedfn](#defpathedfn)
|
||||
- [defprotocolpath](#defprotocolpath)
|
||||
- [extend-protocolpath](#extend-protocolpath)
|
||||
- [fixed-pathed-nav](#fixed-pathed-nav)
|
||||
- [path](#path)
|
||||
- [providepath](#providepath)
|
||||
- [variable-pathed-nav](#variable-pathed-nav)
|
||||
- [Collector Macros](#collector-macros)
|
||||
- [defcollector](#defcollector)
|
||||
- [paramscollector](#paramscollector)
|
||||
- [pathed-collector](#pathed-collector)
|
||||
- [Navigator Macros](#navigator-macros)
|
||||
- [defnav](#defnav)
|
||||
- [defnavconstructor](#defnavconstructor)
|
||||
- [nav](#nav)
|
||||
- [paramsfn](#paramsfn)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
|
|
@ -320,41 +313,6 @@ Declares a new symbol available to be defined as a path. If the path will requir
|
|||
{:a {:b 3}, :c {:d 4, :e {:f 5}}, :g 6}
|
||||
```
|
||||
|
||||
|
||||
## defpathedfn
|
||||
|
||||
`(defpathedfn name & args)`
|
||||
|
||||
Defines a higher order navigator (a function that returns a navigator) that itself takes in one or more paths
|
||||
as input. This macro is generally used in conjunction with [fixed-pathed-nav](#fixed-pathed-nav)
|
||||
or [variable-pathed-nav](#variable-pathed-nav). When inline factoring is applied to a path containing
|
||||
one of these higher order navigators, it will automatically interepret all
|
||||
arguments as paths, factor them accordingly, and set up the callsite to
|
||||
provide the parameters dynamically. Use `^:notpath` metadata on arguments
|
||||
to indicate non-path arguments that should not be factored – note that in order
|
||||
to be inline factorable, these arguments must be statically resolvable (e.g. a
|
||||
top level var).
|
||||
|
||||
The syntax is the same as `defn` (optional docstring, etc.). Note that `defpathedfn` should take **paths** as input. For a parameterized navigator which takes non-path arguments, use [defnavconstructor](#defnavconstructor) to wrap an existing navigator, [defnav](#defnav) to define your own custom navigator, or create a path with late bound parameters using `comp-paths`.
|
||||
|
||||
```clojure
|
||||
;; 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)`
|
||||
|
|
@ -398,27 +356,6 @@ Extends a protocol path `protpath` to a list of types. The `extensions` argument
|
|||
|
||||
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 subcollection of `structure` this navigator selects.
|
||||
|
||||
`transform-impl` must be of the form `(transform* [this structure next-fn] body)`. It should find the result of calling `nextfn` on whatever subcollection of `structure` this navigator selects. Then it should return the result of reconstructing the original structure using the results of the `nextfn` call.
|
||||
|
||||
See [defpathedfn](#defpathedfn) for an example.
|
||||
|
||||
## path
|
||||
|
||||
`(path & path)`
|
||||
|
|
@ -428,43 +365,12 @@ of the path for later re-use (when possible). For almost all idiomatic uses
|
|||
of Specter provides huge speedup. This macro is automatically used by the
|
||||
select/transform/setval/replace-in/etc. macros.
|
||||
|
||||
The arguments to `path` cannot include local symbols (defined in a `let`), dynamic vars, or special forms (like `if`). In these cases, specter will throw an exception detailing what went wrong.
|
||||
|
||||
Any higher order navigators passed to `path` must include their arguments, even if their arguments will be evaluated at runtime. `path` cannot be passed late bound parameters.
|
||||
|
||||
**Note:** In general, you should prefer using `comp-paths` and `select` over `path` and `compiled-select`. `comp-paths` allows late bound parameters, and `path` does not, so `comp-paths` is more flexible. `select` automatically applies `path` to its path arguments, so you do not lose the speed of inline caching (unless you pass a local symbol, dynamic var, or special form). You can ensure you do not do this by calling `(must-cache-paths!)`. You can find a more detailed discussion of inline caching [here](https://github.com/nathanmarz/specter/wiki/Specter-0.11.0:-Performance-without-the-tradeoffs).
|
||||
Any higher order navigators passed to `path` must include their arguments, even if their arguments will be evaluated at runtime.
|
||||
|
||||
```clojure
|
||||
=> (def p (path even?))
|
||||
=> (select [ALL p] (range 10))
|
||||
[0 2 4 6 8]
|
||||
|
||||
=> (def p (let [apred even?] (path apred)))
|
||||
Failed to cache path: Local symbol apred where navigator expected
|
||||
;; Wrap predicate functions in pred to allow caching
|
||||
=> (def p (let [apred even?] (path (pred apred)))) ; No exception thrown
|
||||
=> (def ^:dynamic *apred*)
|
||||
=> (def p (binding [*apred* even?] (path *apred*)))
|
||||
Failed to cache path: Var *apred* is dynamic
|
||||
=> (def p (path (if true even? odd?)))
|
||||
Failed to cache path: Special form (if true even? odd?) where navigator expected
|
||||
;; Replace if with if-path
|
||||
=> (def p (path (if-path (fn [_] true) even? odd?))) ; No exception thrown
|
||||
=> (select [ALL p] (range 10))
|
||||
|
||||
=> (def p (path pred))
|
||||
Failed to cache path: Var pred is not a navigator
|
||||
;; Instead we need to provide pred with its argument, even if the argument
|
||||
;; will not be determined until runtime
|
||||
=> (defn p [apred] (path ALL (pred apred)))
|
||||
;; Use compiled-select because we have precompiled our path
|
||||
=> (compiled-select (p odd?) (range 10))
|
||||
[1 3 5 7 9]
|
||||
|
||||
;; More idiomatic solution of the above
|
||||
=> (def p (comp-paths ALL pred))
|
||||
=> (select (p odd?) (range 10))
|
||||
[1 3 5 7 9]
|
||||
```
|
||||
|
||||
## providepath
|
||||
|
|
@ -473,42 +379,6 @@ Failed to cache path: Var pred is not a navigator
|
|||
|
||||
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 next 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
|
||||
|
|
@ -531,39 +401,6 @@ 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 [path-binding path] collect-val-impl)`
|
||||
|
||||
This helper is used to define collectors that take in a single selector
|
||||
path 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 `path-binding`.
|
||||
|
||||
`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
|
||||
|
|
@ -604,70 +441,10 @@ See also [nav](#nav)
|
|||
[0 2 2 3 4]
|
||||
```
|
||||
|
||||
## defnavconstructor
|
||||
|
||||
`(defnavconstructor name nav-binding params & body)`
|
||||
|
||||
Defines a constructor for a previously defined navigator. Allows for arbitrary specification of the arguments of the navigator.
|
||||
|
||||
Note that `defnavconstructor` takes an optional docstring and metadata in the same form as `clojure.core/defn`.
|
||||
|
||||
`nav-binding` should have the form `[binding navigator]`.
|
||||
|
||||
`params` should be a vector of parameters that your navigator will take as arguments.
|
||||
|
||||
`body` should be a form that returns a navigator.
|
||||
|
||||
```clojure
|
||||
;; A constructor for the walker navigator which adds the requirement that the
|
||||
;; structure be an integer to walker's afn predicate
|
||||
=> (defnavconstructor walk-ints
|
||||
"Arguments passed to this walker's predicate must also be integers to
|
||||
return true."
|
||||
[p walker]
|
||||
[apred]
|
||||
(p #(and (integer? %) (apred %))))
|
||||
=> (select (walk-ints even?) [1 [[[[2]] 3 4]] 5 [6 7] [[[8]]]])
|
||||
(2 4 6 8)
|
||||
=> (select (walk-ints #(< % 5)) (range 7))
|
||||
(0 1 2 3 4)
|
||||
;; A constructor for the pred navigator which takes two predicate functions
|
||||
;; as arguments. If either is satisfied, pred will continue navigation.
|
||||
=> (defnavconstructor or-pred
|
||||
[p pred]
|
||||
[pred1 pred2]
|
||||
(p #(or (pred1 %) (pred2 %))))
|
||||
=> (select [ALL (or-pred even? #(> % 6))] (range 10))
|
||||
[0 2 4 6 7 8 9]
|
||||
```
|
||||
|
||||
## nav
|
||||
|
||||
`(nav params select-impl transform-impl)`
|
||||
|
||||
`(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
|
||||
;; val is the parameter that will be bound at a later time to complete the navigator
|
||||
;; x represents the current structure for the navigator
|
||||
=> (def less-than-n-pred (comp-paths (paramsfn [val] [x] (< x val))))
|
||||
=> (select [ALL (less-than-n-pred 5)] [2 7 3 4 10 8])
|
||||
[2 3 4]
|
||||
=> (select [ALL (less-than-n-pred 9)] [2 7 3 4 10 8])
|
||||
[2 7 3 4 8]
|
||||
=> (transform [ALL (less-than-n-pred 9)] inc [2 7 3 4 10 8])
|
||||
[3 8 4 5 10 9]
|
||||
;; bot and top are late bound parameters
|
||||
;; x represents the current structure for the navigator
|
||||
=> (def between (comp-paths (paramsfn [bot top] [x] (and (< bot x) (< x top)))))
|
||||
=> (select [ALL (between 1 5)] (range 10))
|
||||
[2 3 4]
|
||||
```
|
||||
Returns an "anonymous navigator." See [defnav](#defnav).
|
||||
Loading…
Reference in a new issue