From 553a835fd7fcddfc3c261e99268ed63a2a8af4d6 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Wed, 24 Jun 2015 18:02:05 -0400 Subject: [PATCH] fix readme with update->transform change --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f5684d6..c674d5d 100644 --- a/README.md +++ b/README.md @@ -37,21 +37,21 @@ user> (select [:a ALL odd?] [1 3 5] ``` -Another function called `update` is used to perform a transformation on a data structure. In addition to a selector, it takes in an "update function" which specifies what to do with each element navigated to. For example, here's how to increment all the even values for :a keys in a sequence of maps: +Another function called `transform` is used to perform a transformation on a data structure. In addition to a selector, it takes in an "transform function" which specifies what to do with each element navigated to. For example, here's how to increment all the even values for :a keys in a sequence of maps: ```clojure -user> (update [ALL :a even?] +user> (transform [ALL :a even?] inc [{:a 1} {:a 2} {:a 4} {:a 3}]) [{:a 1} {:a 3} {:a 5} {:a 3}] ``` -Here's another example of update: +Here's another example of transform: ```clojure user> (use 'com.rpl.specter) nil -user> (update [:a ALL odd?] +user> (transform [:a ALL odd?] dec {:a [1 2 3 5] :b :c}) {:b :c, :a [0 2 2 4]} @@ -60,29 +60,29 @@ user> (update [:a ALL odd?] Specter comes with all sorts of built-in ways of navigating data structures. For example, here's how to increment the last odd number in a sequence: ```clojure -user> (update [(filterer odd?) LAST] +user> (transform [(filterer odd?) LAST] inc [2 1 3 6 9 4 8]) [2 1 3 6 10 4 8] ``` -`filterer` navigates you to a view of the sequence currently being looked at. `LAST` navigates you to the last element of whatever sequence you're looking at. But of course during updates, the updates are performed on the original data structure. +`filterer` navigates you to a view of the sequence currently being looked at. `LAST` navigates you to the last element of whatever sequence you're looking at. But of course during transforms, the transforms are performed on the original data structure. `srange` is a selector for looking at or replacing a subsequence of a sequence. For example, here's how to increment all the odd numbers between indexes 1 (inclusive) and 4 (exclusive): ```clojure -user> (update [(srange 1 4) ALL odd?] inc [0 1 2 3 4 5 6 7]) +user> (transform [(srange 1 4) ALL odd?] inc [0 1 2 3 4 5 6 7]) [0 2 2 4 4 5 6 7] ``` `srange` can also be used to replace that subsequence entirely with a new sequence. For example, here's how to replace the subsequence from index 2 to 4 with [-1 -1 -1]: ```clojure -user> (update (srange 2 4) (fn [_] [-1 -1 -1]) [0 1 2 3 4 5 6 7 8 9]) +user> (transform (srange 2 4) (fn [_] [-1 -1 -1]) [0 1 2 3 4 5 6 7 8 9]) [0 1 -1 -1 -1 4 5 6 7 8 9] ``` -The above can be written more concisely using the `setval` function, which is a wrapper around `update`: +The above can be written more concisely using the `setval` function, which is a wrapper around `transform`: ```clojure user> (setval (srange 2 4) [-1 -1 -1] [0 1 2 3 4 5 6 7 8 9]) @@ -106,16 +106,16 @@ user> (select (walker number?) [2 1 2 1 2 6 7 4] ``` -When doing more involved transformations, you often find you lose context when navigating deep within a data structure and need information "up" the data structure to perform the transformation. Specter solves this problem by allowing you to collect values during navigation to use in the update function. Here's an example which transforms a sequence of maps by adding the value of the :b key to the value of the :a key, but only if the :a key is even: +When doing more involved transformations, you often find you lose context when navigating deep within a data structure and need information "up" the data structure to perform the transformation. Specter solves this problem by allowing you to collect values during navigation to use in the transform function. Here's an example which transforms a sequence of maps by adding the value of the :b key to the value of the :a key, but only if the :a key is even: ```clojure -user> (update [ALL (collect-one :b) :a even?] +user> (transform [ALL (collect-one :b) :a even?] + [{:a 1 :b 3} {:a 2 :b -10} {:a 4 :b 10} {:a 3}]) [{:b 3, :a 1} {:b -10, :a -8} {:b 10, :a 14} {:a 3}] ``` -The update function receives as arguments all the collected values followed by the navigated to value. So in this case `+` receives the value of the :b key followed by the value of the :a key, and the update is performed to :a's value. +The transform function receives as arguments all the collected values followed by the navigated to value. So in this case `+` receives the value of the :b key followed by the value of the :a key, and the transform is performed to :a's value. The four built-in ways for collecting values are `VAL`, `collect`, `collect-one`, and `putval`. `VAL` just adds whatever element it's currently on to the value list, while `collect` and `collect-one` take in a selector to navigate to the desired value. `collect` works just like `select` by finding a sequence of values, while `collect-one` expects to only navigate to a single value. Finally, `putval` adds an external value into the collected values list. @@ -124,7 +124,7 @@ To make your own selector, implement the `StructurePath` protocol which looks li ```clojure (defprotocol StructurePath (select* [this structure next-fn]) - (update* [this structure next-fn]) + (transform* [this structure next-fn]) ) ``` @@ -135,20 +135,20 @@ As an example, here is how Clojure keywords implement this protocol: StructurePath (select* [kw structure next-fn] (next-fn (get structure kw))) - (update* [kw structure next-fn] + (transform* [kw structure next-fn] (assoc structure kw (next-fn (get structure kw))) )) ``` -`next-fn` represents the rest of the select or update, respectively. As you can see, this implementation perfectly captures what it means to navigate via a keyword within a data structure. In the select case, it completes the select by calling `next-fn` on the value of the keyword. In the update case, it updates the nested data structure using next-fn and then replaces the current value of the keyword with that updated data structure. +`next-fn` represents the rest of the select or transform, respectively. As you can see, this implementation perfectly captures what it means to navigate via a keyword within a data structure. In the select case, it completes the select by calling `next-fn` on the value of the keyword. In the transform case, it transforms the nested data structure using next-fn and then replaces the current value of the keyword with that transformed data structure. -Finally, you can make `select` and `update` work much faster by precompiling your selectors using the `comp-paths` function. There's about a 3x speed difference between the following two invocations of update: +Finally, you can make `select` and `transform` work much faster by precompiling your selectors using the `comp-paths` function. There's about a 3x speed difference between the following two invocations of transform: ```clojure (def precompiled (comp-paths ALL :a even?)) -(update [ALL :a even?] inc structure) -(compiled-update precompiled inc structure) +(transform [ALL :a even?] inc structure) +(compiled-transform precompiled inc structure) ``` Depending on the details of the selector and the data being transformed, precompiling can sometimes provide more than a 10x speedup. @@ -157,7 +157,7 @@ Some more examples: Decrement every value in a map: ```clojure -user> (update [ALL LAST] +user> (transform [ALL LAST] dec {:a 1 :b 3}) {:b 2 :a 0} @@ -165,7 +165,7 @@ user> (update [ALL LAST] Increment the value for :a key by 10: ```clojure -user> (update [:a (putval 10)] +user> (transform [:a (putval 10)] + {:a 1 :b 3}) {:b 3 :a 11} @@ -191,14 +191,14 @@ user> (setval [ALL For every map in a sequence, increment every number in :c's value if :a is even or increment :d if :a is odd: ```clojure -user> (update [ALL (if-path [:a even?] [:c ALL] :d)] +user> (transform [ALL (if-path [:a even?] [:c ALL] :d)] inc [{:a 2 :c [1 2] :d 4} {:a 4 :c [0 10 -1]} {:a -1 :c [1 1 1] :d 1}]) [{:c [2 3], :d 4, :a 2} {:c [1 11 0], :a 4} {:c [1 1 1], :d 2, :a -1}] ``` # Future work -- Make it possible to parallelize selects/updates +- Make it possible to parallelize selects/transforms - Any connection to transducers? - Add Clojurescript compatibility