Repository: sanctuary-js/sanctuary (js)

Issue:
takeWhile and dropWhile
The Ramda functions [takeWhile](http://ramdajs.com/docs/#takeWhile) and [dropWhile](http://ramdajs.com/docs/#dropWhile) should both have the type signature:
```javascript
(a -> Boolean) -> List a -> List a
```

I mentioned `takeUntil` and `dropUntil` in the Gitter room, but thinking on it more they don't bring much to the table (the way I was thinking of them):

```javascript
const takeUntil = pred => S.takeWhile(S.complement(pred));
```

Pull request description:
foldable: add S.takeWhile and S.dropWhile
Closes #349

Patch:
diff --git a/index.js b/index.js
index 824fa6f..f59e9ac 100644
--- a/index.js
+++ b/index.js
@@ -1039,6 +1039,70 @@
       [Fn(a, $.Boolean), m(a), m(a)],
       Z.filterM);
 
+  //# takeWhile :: (Foldable f, Alternative f) => (a -> Boolean) -> f a -> f a
+  //.
+  //. Discards the first inner value which does not satisfy the predicate, and
+  //. all subsequent inner values.
+  //.
+  //. ```javascript
+  //. > S.takeWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4])
+  //. [3, 3, 3, 7]
+  //.
+  //. > S.takeWhile(S.even, [3, 3, 3, 7, 6, 3, 5, 4])
+  //. []
+  //. ```
+  function Array$takeWhile(pred, xs) {
+    var idx = 0;
+    while (idx < xs.length && pred(xs[idx])) idx += 1;
+    return xs.slice(0, idx);
+  }
+
+  function takeWhile(pred, xs) {
+    if (Array.isArray(xs)) return Array$takeWhile(pred, xs);
+    var done = false;
+    function takeWhileReducer(xs, x) {
+      return !done && pred(x) ? append(x, xs) : (done = true, xs);
+    }
+    return Z.reduce(takeWhileReducer, Z.empty(xs.constructor), xs);
+  }
+  S.takeWhile =
+  def('takeWhile',
+      {f: [Z.Foldable, Z.Alternative]},
+      [Pred(a), f(a), f(a)],
+      takeWhile);
+
+  //# dropWhile :: (Foldable f, Alternative f) => (a -> Boolean) -> f a -> f a
+  //.
+  //. Retains the first inner value which does not satisfy the predicate, and
+  //. all subsequent inner values.
+  //.
+  //. ```javascript
+  //. > S.dropWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4])
+  //. [6, 3, 5, 4]
+  //.
+  //. > S.dropWhile(S.even, [3, 3, 3, 7, 6, 3, 5, 4])
+  //. [3, 3, 3, 7, 6, 3, 5, 4]
+  //. ```
+  function Array$dropWhile(pred, xs) {
+    var idx = 0;
+    while (idx < xs.length && pred(xs[idx])) idx += 1;
+    return xs.slice(idx);
+  }
+
+  function dropWhile(pred, xs) {
+    if (Array.isArray(xs)) return Array$dropWhile(pred, xs);
+    var done = false;
+    function dropWhileReducer(xs, x) {
+      return !done && pred(x) ? xs : (done = true, append(x, xs));
+    }
+    return Z.reduce(dropWhileReducer, Z.empty(xs.constructor), xs);
+  }
+  S.dropWhile =
+  def('dropWhile',
+      {f: [Z.Foldable, Z.Alternative]},
+      [Pred(a), f(a), f(a)],
+      dropWhile);
+
   //. ### Combinator
 
   //# I :: a -> a


Test patch:
diff --git a/test/dropWhile.js b/test/dropWhile.js
new file mode 100644
index 0000000..cc33a1f
--- /dev/null
+++ b/test/dropWhile.js
@@ -0,0 +1,22 @@
+'use strict';
+
+var S = require('..');
+
+var eq = require('./internal/eq');
+
+
+test('dropWhile', function() {
+
+  eq(typeof S.dropWhile, 'function');
+  eq(S.dropWhile.length, 2);
+  eq(S.dropWhile.toString(), 'dropWhile :: (Foldable f, Alternative f) => (a -> Boolean) -> f a -> f a');
+
+  eq(S.dropWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4]), [6, 3, 5, 4]);
+  eq(S.dropWhile(S.even, [3, 3, 3, 7, 6, 3, 5, 4]), [3, 3, 3, 7, 6, 3, 5, 4]);
+  eq(S.dropWhile(S.odd, []), []);
+
+  eq(S.dropWhile(S.odd, S.Just(1)), S.Nothing);
+  eq(S.dropWhile(S.even, S.Just(1)), S.Just(1));
+  eq(S.dropWhile(S.odd, S.Nothing), S.Nothing);
+
+});
diff --git a/test/takeWhile.js b/test/takeWhile.js
new file mode 100644
index 0000000..220ede2
--- /dev/null
+++ b/test/takeWhile.js
@@ -0,0 +1,22 @@
+'use strict';
+
+var S = require('..');
+
+var eq = require('./internal/eq');
+
+
+test('takeWhile', function() {
+
+  eq(typeof S.takeWhile, 'function');
+  eq(S.takeWhile.length, 2);
+  eq(S.takeWhile.toString(), 'takeWhile :: (Foldable f, Alternative f) => (a -> Boolean) -> f a -> f a');
+
+  eq(S.takeWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4]), [3, 3, 3, 7]);
+  eq(S.takeWhile(S.even, [3, 3, 3, 7, 6, 3, 5, 4]), []);
+  eq(S.takeWhile(S.odd, []), []);
+
+  eq(S.takeWhile(S.odd, S.Just(1)), S.Just(1));
+  eq(S.takeWhile(S.even, S.Just(1)), S.Nothing);
+  eq(S.takeWhile(S.odd, S.Nothing), S.Nothing);
+
+});