Repository: calmm-js/partial.lenses
Pull request #65 (2017-03-17 13:40:35)

Renamed experimental `L.first` and `L.firstAs`
Renamed experimental `L.first` and `L.firstAs` as follows:

```diff
-L.first
+L.select

-L.firstAs
+L.selectAs
```

This was done to avoid confusing the operations on traversals with the newly
added `L.last` lens on array-like objects.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5892fab..b828363 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
 # Changelog
 
+## 9.8.0
+
+Renamed experimental `L.first` and `L.firstAs` as follows:
+
+```diff
+-L.first
++L.select
+
+-L.firstAs
++L.selectAs
+```
+
+This was done to avoid confusing the operations on traversals with the newly
+added `L.last` lens on array-like objects.
+
 ## 9.3.0
 
 Obsoleted `L.to` and `L.just`.  You can now directly compose optics with
diff --git a/README.md b/README.md
index f34e269..cbb329a 100644
--- a/README.md
+++ b/README.md
@@ -63,14 +63,16 @@ parts.  [Try Lenses!](https://calmm-js.github.io/partial.lenses/playground.html)
       * [`L.collect(traversal, maybeData) ~> [...values]`](#L-collect "L.collect: PTraversal s a -> Maybe s -> [a]")
       * [`L.collectAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> [...values]`](#L-collectAs "L.collectAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> [b]")
       * [`L.count(traversal, maybeData) ~> number`](#L-count "L.count: PTraversal s a -> Number")
-      * [`L.first(traversal, maybeData) ~> maybeValue`](#L-first "L.first: PTraversal s a -> Maybe s -> Maybe a")
-      * [`L.firstAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> maybeValue`](#L-firstAs "L.firstAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> Maybe b")
+      * ~~[`L.first(traversal, maybeData) ~> maybeValue`](#L-first "L.first: PTraversal s a -> Maybe s -> Maybe a")~~
+      * ~~[`L.firstAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> maybeValue`](#L-firstAs "L.firstAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> Maybe b")~~
       * [`L.foldl((value, maybeValue, index) => value, value, traversal, maybeData) ~> value`](#L-foldl "L.foldl: ((r, Maybe a, Index) -> r) -> r -> PTraversal s a -> Maybe s -> r")
       * [`L.foldr((value, maybeValue, index) => value, value, traversal, maybeData) ~> value`](#L-foldr "L.foldr: ((r, Maybe a, Index) -> r) -> r -> PTraversal s a -> Maybe s -> r")
       * [`L.maximum(traversal, maybeData) ~> maybeValue`](#L-maximum "L.maximum: Ord a => PTraversal s a -> Maybe s -> Maybe a")
       * [`L.minimum(traversal, maybeData) ~> maybeValue`](#L-minimum "L.minimum: Ord a => PTraversal s a -> Maybe s -> Maybe a")
       * [`L.or(traversal, maybeData) ~> boolean`](#L-or "L.or: PTraversal s Boolean -> Boolean")
       * [`L.product(traversal, maybeData) ~> number`](#L-product "L.product: PTraversal s Number -> Maybe s -> Number")
+      * [`L.select(traversal, maybeData) ~> maybeValue`](#L-select "L.select: PTraversal s a -> Maybe s -> Maybe a")
+      * [`L.selectAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> maybeValue`](#L-selectAs "L.selectAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> Maybe b")
       * [`L.sum(traversal, maybeData) ~> number`](#L-sum "L.sum: PTraversal s Number -> Maybe s -> Number")
     * [Creating new traversals](#creating-new-traversals)
       * [`L.branch({prop: traversal, ...props}) ~> traversal`](#L-branch "L.branch: {p1: PTraversal s a, ...pts} -> PTraversal s a")
@@ -1285,7 +1287,9 @@ L.count([L.elems, "x"], [{x: 11}, {y: 12}])
 // 1
 ```
 
-##### <a id="L-first"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-first) [`L.first(traversal, maybeData) ~> maybeValue`](#L-first "L.first: PTraversal s a -> Maybe s -> Maybe a")
+##### <a id="L-first"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-first) ~~[`L.first(traversal, maybeData) ~> maybeValue`](#L-first "L.first: PTraversal s a -> Maybe s -> Maybe a")~~
+
+**WARNING: `first` has been renamed [`select`](#L-select).**
 
 `L.first` goes lazily over the elements focused on by the given traversal and
 returns the first non-`undefined` element.
@@ -1297,9 +1301,9 @@ L.first([L.elems, "y"], [{x:1},{y:2},{z:3}])
 
 Note that `L.first` is equivalent to [`L.firstAs(R.identity)`](#L-firstAs).
 
-**WARNING: Lazy folds over traversals are experimental.**
+##### <a id="L-firstAs"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-firstAs) ~~[`L.firstAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> maybeValue`](#L-firstAs "L.firstAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> Maybe b")~~
 
-##### <a id="L-firstAs"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-firstAs) [`L.firstAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> maybeValue`](#L-firstAs "L.firstAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> Maybe b")
+**WARNING: `firstAs` has been renamed [`selectAs`](#L-selectAs).**
 
 `L.firstAs` goes lazily over the elements focused on by the given traversal,
 applying the given function to each element, and returns the first
@@ -1332,8 +1336,6 @@ all(x => x < 9,
 // true
 ```
 
-**WARNING: Lazy folds over traversals are experimental.**
-
 ##### <a id="L-foldl"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-foldl) [`L.foldl((value, maybeValue, index) => value, value, traversal, maybeData) ~> value`](#L-foldl "L.foldl: ((r, Maybe a, Index) -> r) -> r -> PTraversal s a -> Maybe s -> r")
 
 `L.foldl` performs a fold from left over the elements focused on by the given
@@ -1411,6 +1413,55 @@ L.product(L.elems, [1,2,3])
 // 6
 ```
 
+##### <a id="L-select"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-select) [`L.select(traversal, maybeData) ~> maybeValue`](#L-select "L.select: PTraversal s a -> Maybe s -> Maybe a")
+
+`L.select` goes lazily over the elements focused on by the given traversal and
+returns the select non-`undefined` element.
+
+```js
+L.select([L.elems, "y"], [{x:1},{y:2},{z:3}])
+// 2
+```
+
+Note that `L.select` is equivalent to [`L.selectAs(R.identity)`](#L-selectAs).
+
+**WARNING: Lazy folds over traversals are experimental.**
+
+##### <a id="L-selectAs"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-selectAs) [`L.selectAs((maybeValue, index) => maybeValue, traversal, maybeData) ~> maybeValue`](#L-selectAs "L.selectAs: ((Maybe a, Index) -> Maybe b) -> PTraversal s a -> Maybe s -> Maybe b")
+
+`L.selectAs` goes lazily over the elements focused on by the given traversal,
+applying the given function to each element, and returns the select
+non-`undefined` value returned by the function.
+
+```js
+L.selectAs(x => x > 3 ? -x : undefined, L.elems, [3,1,4,1,5])
+// -4
+```
+
+`L.selectAs` operates lazily.  The user specified function is only applied to
+elements until the select non-`undefined` value is returned and after that
+`L.selectAs` returns without examining more elements.
+
+Note that `L.selectAs` can be used to implement many other operations over
+traversals such as finding an element matching a predicate and checking whether
+all/any elements match a predicate.  For example, here is how you could
+implement a for all predicate over traversals:
+
+```js
+const all = R.curry((p, t, s) => !L.selectAs(x => p(x) ? undefined : true, t, s))
+```
+
+Now:
+
+```js
+all(x => x < 9,
+    flatten,
+    [[[1], 2], {y: 3}, [{l: 4, r: [5]}, {x: 6}]])
+// true
+```
+
+**WARNING: Lazy folds over traversals are experimental.**
+
 ##### <a id="L-sum"></a> [≡](#contents) [▶](https://calmm-js.github.io/partial.lenses/#L-sum) [`L.sum(traversal, maybeData) ~> number`](#L-sum "L.sum: PTraversal s Number -> Maybe s -> Number")
 
 `L.sum` computes the sum of the optional numbers targeted by the traversal.
diff --git a/bench/bench.js b/bench/bench.js
index 0d55ad6..96ff021 100644
--- a/bench/bench.js
+++ b/bench/bench.js
@@ -243,11 +243,11 @@ R.forEach(bs => {
     `R.set(l_x_y_z, 0, xyzn)`,
     `R.set(l_xyz, 0, xyzn)`,
   ], [
-    `L.firstAs(x => x > 3 ? x : undefined, L.elems, xs100)`,
+    `L.selectAs(x => x > 3 ? x : undefined, L.elems, xs100)`,
     `R.find(x => x > 3, xs100)`,
     `O.Fold.findOf(O.Traversal.traversed, x => x > 3, xs100)`,
   ], [
-    `L.firstAs(x => x < 3 ? x : undefined, L.elems, xs100)`,
+    `L.selectAs(x => x < 3 ? x : undefined, L.elems, xs100)`,
     `R.find(x => x < 3, xs100)`,
     [`O.Fold.findOf(O.Traversal.traversed, x => x < 3, xs100)`, "NO SHORTCUT EVALUATION"],
   ], [
@@ -321,7 +321,7 @@ R.forEach(bs => {
   ], [
     `L.modify(flatten, inc, xsss100)`,
   ], [
-    `L.firstAs(x => x > 3 ? x : undefined, L.elems, pi)`,
+    `L.selectAs(x => x > 3 ? x : undefined, L.elems, pi)`,
     `R.find(x => x > 3, pi)`,
     `O.Fold.findOf(O.Traversal.traversed, x => x > 3, pi)`,
   ], [
diff --git a/src/partial.lenses.js b/src/partial.lenses.js
index 1121ee5..e121248 100644
--- a/src/partial.lenses.js
+++ b/src/partial.lenses.js
@@ -174,12 +174,12 @@ function the(v) {
 const T = the(true)
 const not = x => !x
 
-const First = ConcatOf((l, r) => l && l() || r && r(), void 0, id)
+const Select = ConcatOf((l, r) => l && l() || r && r(), void 0, id)
 
-const mkFirst = toM => (xi2yM, t, s) => {
+const mkSelect = toM => (xi2yM, t, s) => {
   if (process.env.NODE_ENV !== "production")
-    warn(mkFirst, "Lazy folds over traversals are experimental")
-  return (s = run(t, First, pipe2U(xi2yM, toM), s),
+    warn(mkSelect, "Lazy folds over traversals are experimental")
+  return (s = run(t, Select, pipe2U(xi2yM, toM), s),
           s && (s = s()) && s.v)
 }
 
@@ -596,11 +596,11 @@ export const merge = process.env.NODE_ENV === "production" ? concat : (m, t, d)
 
 // Folds over traversals
 
-export const all = pipe2U(mkFirst(x => x ? void 0 : T), not)
+export const all = pipe2U(mkSelect(x => x ? void 0 : T), not)
 
 export const and = all(id)
 
-export const any = pipe2U(mkFirst(x => x ? T : void 0), Boolean)
+export const any = pipe2U(mkSelect(x => x ? T : void 0), Boolean)
 
 export const collectAs = curry((xi2y, t, s) =>
   toArray(run(t, Collect, xi2y, s)) || [])
@@ -609,10 +609,6 @@ export const collect = collectAs(id)
 
 export const count = concatAs(x => void 0 !== x ? 1 : 0, Sum)
 
-export const firstAs = curry(mkFirst(x => void 0 !== x ? the(x) : x))
-
-export const first = firstAs(id)
-
 export const foldl = curry((f, r, t, s) =>
   fold(f, r, run(t, Collect, pair, s)))
 
@@ -633,6 +629,18 @@ export const or = any(id)
 
 export const product = concatAs(unto(1), Monoid((y, x) => x * y, 1))
 
+export const selectAs = curry(mkSelect(x => void 0 !== x ? the(x) : x))
+
+export const select = selectAs(id)
+
+export const firstAs = process.env.NODE_ENV === "production" ? selectAs : curry((f, t, d) =>
+  warn(firstAs, "`firstAs` has been renamed `selectAs`") ||
+  selectAs(f, t, d))
+
+export const first = process.env.NODE_ENV === "production" ? select : curry((t, d) =>
+  warn(first, "`first` has been renamed `select`") ||
+  select(t, d))
+
 export const sum = concatAs(unto(0), Sum)
 
 // Creating new traversals


Test patch:
diff --git a/test/core.js b/test/core.js
index cba003a..eea9ba3 100644
--- a/test/core.js
+++ b/test/core.js
@@ -83,10 +83,6 @@ export const and = all(R.identity)
 
 export const any = L.any
 
-export const firstAs = L.firstAs
-
-export const first = L.firstAs(R.identity)
-
 export const foldl = foldx(R.pipe)
 export const foldr = foldx(R.compose)
 
@@ -104,6 +100,12 @@ export const or = any(R.identity)
 export const product = concatDefined({empty: () => 1, concat: R.multiply})
 export const sum = concatDefined(Sum)
 
+export const selectAs = L.selectAs
+export const select = selectAs(R.identity)
+
+export const first = select
+export const firstAs = selectAs
+
 // Creating new traversals
 
 export const branch = L.branch
diff --git a/test/tests.js b/test/tests.js
index c45c9f9..6ee1f10 100644
--- a/test/tests.js
+++ b/test/tests.js
@@ -199,6 +199,8 @@ describe("arities", () => {
     replace: 2,
     required: 1,
     rewrite: 1,
+    select: 2,
+    selectAs: 3,
     seq: 0,
     set: 3,
     slice: 2,
@@ -799,20 +801,22 @@ describe("seq", () => {
 })
 
 describe("lazy folds", () => {
-  testEq(`L.first(L.elems, [])`, undefined)
-  testEq(`L.first(L.values, {})`, undefined)
-  testEq(`L.firstAs((x, i) => x > 3 ? [x + 2, i] : undefined,
-                    L.elems,
-                    [3, 1, 4, 1, 5])`,
+  testEq(`L.select(L.elems, [])`, undefined)
+  testEq(`L.select(L.values, {})`, undefined)
+  testEq(`X.first(L.values, {})`, undefined)
+  testEq(`L.selectAs((x, i) => x > 3 ? [x + 2, i] : undefined,
+                     L.elems,
+                     [3, 1, 4, 1, 5])`,
          [6, 2])
-  testEq(`L.firstAs((x, i) => x > 3 ? [x + 2, i] : undefined,
-                    L.values,
-                    {a:3, b:1, c:4, d:1, e:5})`,
+  testEq(`L.selectAs((x, i) => x > 3 ? [x + 2, i] : undefined,
+                     L.values,
+                     {a:3, b:1, c:4, d:1, e:5})`,
          [6, "c"])
-  testEq(`L.firstAs(x => {}, L.values, {x:1})`, undefined)
-  testEq(`L.firstAs(x => x < 9 ? undefined : [x],
-                    flatten,
-                    [[[1], 2], {y: 3}, [{l: 41, r: [5]}, {x: 6}]])`,
+  testEq(`L.selectAs(x => {}, L.values, {x:1})`, undefined)
+  testEq(`X.firstAs(x => {}, L.values, {x:1})`, undefined)
+  testEq(`L.selectAs(x => x < 9 ? undefined : [x],
+                     flatten,
+                     [[[1], 2], {y: 3}, [{l: 41, r: [5]}, {x: 6}]])`,
         [41])
 
   testEq(`L.any((x, i) => x > i, L.elems, [0,1,3])`, true)
@@ -830,4 +834,4 @@ describe("L.last", () => {
   testEq(`L.set(L.last, 5, undefined)`, [5])
   testEq(`L.set(L.last, 5, [])`, [5])
   testEq(`L.set(L.last, 5, [1,2])`, [1,5])
-})
\ No newline at end of file
+})
diff --git a/test/types.js b/test/types.js
index b8b4fcb..21c2f21 100644
--- a/test/types.js
+++ b/test/types.js
@@ -124,13 +124,6 @@ export const collectAs = T.fn([T.fn([T_maybeData, T_index], T_maybeData),
 
 export const count = T.fn([T_traversal, T_maybeData], T.number)
 
-export const firstAs =
-  T.fn([T.fn([T_maybeData, T_index], T.any),
-        T_traversal,
-        T_maybeData],
-       T.any)
-export const first = T.fn([T_traversal, T_maybeData], T.any)
-
 export const foldl =
   T.fn([T.fn([T.any, T_maybeData, T_index], T.any),
         T.any,
@@ -147,6 +140,16 @@ export const or = T.fn([T_traversal, T_maybeData], T.boolean)
 export const product = count
 export const sum = count
 
+export const select = T.fn([T_traversal, T_maybeData], T.any)
+export const selectAs =
+  T.fn([T.fn([T_maybeData, T_index], T.any),
+        T_traversal,
+        T_maybeData],
+       T.any)
+
+export const first = select
+export const firstAs = selectAs
+
 // Creating new traversals
 
 export const branch = T.fn([T.props(T_traversal)], T_traversal)