Skip to content

Conversation

@gabejohnson
Copy link
Member

Closes #349

@gabejohnson
Copy link
Member Author

I put these two functions near filter as I think they deal with Foldable, take a predicate and "reduce" the collection (in the case of Array).

index.js Outdated
[Fn(a, $.Boolean), m(a), m(a)],
Z.filterM);

//# takeWhile :: (Foldable f, Monoid (f a)) => (a -> Boolean) -> f a -> f a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: There's an extra space after the =>.

index.js Outdated

//# takeWhile :: (Foldable f, Monoid (f a)) => (a -> Boolean) -> f a -> f a
//.
//. Returns the first elements for which the predicate returns true.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't sound quite right to me for a non-array argument. How about the following?

Discards the first inner value which does not satisfy the predicate, and all subsequent inner values.

index.js Outdated
//.
//. ```javascript
//. > S.takeWhile(c => c < 'c', ['a', 'b', 'c', 'd', 'e'])
//. ['a', 'b']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c => c < 'c' is slightly confusing due to c being used in two ways. n => n < 3 with [1, 2, 3, 4, 5] would be clearer. Even better, though, would be to use an example which demonstrates how this differs from filter:

> S.takeWhile(S.odd, [3, 3, 3, 7, 6, 3, 5, 4])
[3, 3, 3, 7]

index.js Outdated
//. Just(1)
//.
//. > S.takeWhile(S.K(false), S.Just(1))
//. Nothing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a predicate which references its argument?

> S.takeWhile(S.odd, S.Just(1))
Just(1)

> S.takeWhile(S.odd, S.Just(2))
Nothing

I don't think we should include these examples, though, as they would be better expressed with filter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to show an example of using a non-array. If we're not allowing strings, I can't think of a good example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's okay to provide array examples only.

index.js Outdated
function takeWhile(p, xs) {
if (Array.isArray(xs)) {
var result = [];
if (xs.length === 0) return result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably makes more sense to create the result array after checking the length of xs.

index.js Outdated
function dropWhile(p, xs) {
if (Array.isArray(xs)) {
if (xs.length === 0) return [];
for (var i = 0; i < xs.length && p(xs[i]); i += 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think idx is preferred over i.

index.js Outdated
//. > S.takeWhile(S.K(false), S.Just(1))
//. Nothing
//. ```
function takeWhile(p, xs) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's :%s/\<p\>/pred/gc for consistency with existing code.

index.js Outdated
if (Array.isArray(xs)) {
var result = [];
if (xs.length === 0) return result;
for (var i = 0, x; i < xs.length && p(x = xs[i]); i += 1) result.push(x);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's :%s/\<i\>/idx/gc for consistency with existing code.

Copy link
Member

@svozza svozza Feb 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, I did a search on the code we have and neither of our for loops use idx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't currently have a single for loop which uses an index variable. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess they're all in sanctuary-type-classes now.

index.js Outdated
function takeWhile(p, xs) {
if (Array.isArray(xs)) {
var result = [];
if (xs.length === 0) return result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I get for submitting a PR while on cold medicine 🤧

index.js Outdated
//. ```
function dropWhile(p, xs) {
if (Array.isArray(xs)) {
if (xs.length === 0) return [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is unnecessary.

index.js Outdated
}
var drop = true;
function dropWhileReducer(xs, x) {
return drop && p(x) ? xs : (drop = false, append(x, xs));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a bit clearer, do you think?

return (drop = drop && p(x)) ? xs : append(x, xs);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if a good idea, but could we borrow generators' nomenclature and go with done here? In that case this reads clearer to me:

// takeWhile
return !done && p(x) ? append(x, xs) : (done = true, xs);

// dropWhile
return !done && p(x) ? xs : (done = true, append(x, xs));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @cust0dian has the clearest statement using done and the assignment in the binary expression at the end. done = true is very explicit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the use of done. :)

eq(S.takeWhile(lt(3), [1, 2, 3, 4, 5]), [1, 2]);
eq(S.takeWhile(lt(4), [1, 2, 3, 4, 5]), [1, 2, 3]);
eq(S.takeWhile(lt(5), [1, 2, 3, 4, 5]), [1, 2, 3, 4]);
eq(S.takeWhile(lt(6), [1, 2, 3, 4, 5]), [1, 2, 3, 4, 5]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change these to demonstrate and assert that takeWhile is different from filter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine. I'll have to keep the tests using Maybe to maintain code coverage.

@gabejohnson gabejohnson force-pushed the add-takeWhile-dropWhile branch from ec3176a to 1a31f4f Compare February 27, 2017 14:49
@gabejohnson
Copy link
Member Author

This should be ready to go.

index.js Outdated
idx < xs.length && pred(x = xs[idx]);
idx += 1) result.push(x);
return result;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to a separate function:

function Array$takeWhile(pred, xs) {
  ...
}
function takeWhile(pred, xs) {
  if (Array.isArray(xs)) return Array$takeWhile(pred, xs);
  ...
}
S.takeWhile =
def(...);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use xs.slice(idx) rather than push repeatedly?

Copy link
Member Author

@gabejohnson gabejohnson Mar 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd prefer Array$takeWhile to a generic findIndex? The definition of Array$takeWhile and Array$dropWhile will be nearly identical save the arguments to slice.

We don't have to expose it.

Copy link
Member Author

@gabejohnson gabejohnson Mar 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plus we can just remove it once support for IE is dropped...in 2025 😜

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took the liberty of going the findIndex route. I can change it if you feel strongly.

index.js Outdated
[Fn(a, $.Boolean), m(a), m(a)],
Z.filterM);

//# takeWhile :: (Foldable f, Monoid (f a)) => (a -> Boolean) -> f a -> f a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should replace Monoid (f a) with Alternative f for the reason given in sanctuary-js/sanctuary-type-classes#37.

Copy link
Member

@safareli safareli Mar 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we updated the type signature without switching from Z.empty to Z.zero. I'll rectify this in the pull request I'll soon open for sanctuary-type-classes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, given our concat-based implementation I think Monoid (f a) is the correct constraint after all. We could have a chain-based takeWhileM (to match filterM) but it seems excessive to provide two versions of a function which is only used occasionally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabejohnson gabejohnson force-pushed the add-takeWhile-dropWhile branch from 1a31f4f to 19e8fb3 Compare March 6, 2017 19:06
index.js Outdated
function Array$findIndex(pred, xs) {
for (var idx = 0; idx < xs.length && pred(xs[idx]); idx += 1);
return idx;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect Array$findIndex(x => x === 42, [1, 2, 3]) to evaluate to -1 rather than to 0. It seems this function isn't quite Array#findIndex after all.

Copy link
Member Author

@gabejohnson gabejohnson Mar 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. Even returning -1 it would still be incorrect. I was naming it findIndex but I can't really think of a good name for it...findFirstFailingIndexMinusOne.

I'll make Array$takeWhile and Array$dropWhile instead.

@gabejohnson gabejohnson force-pushed the add-takeWhile-dropWhile branch from 19e8fb3 to 04df4f5 Compare March 7, 2017 04:04
index.js Outdated
//. []
//. ```
function Array$takeWhile(pred, xs) {
for (var idx = 0; idx < xs.length && pred(xs[idx]); idx += 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference is to only declare block-scoped variables in loops (even though we don't actually have block scoping without let). Since we refer to idx outside the loop I'd like to declare it outside the loop:

var idx = 0;
for (; idx < xs.length && pred(xs[idx]); idx += 1) {}

It would then make sense to switch to a while loop, as it would remove the awkward empty block:

var idx = 0;
while (idx < xs.length && pred(xs[idx])) idx += 1;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty block is unnecessary. It can be replaced by a semicolon. But I'll make the change nonetheless.

@davidchambers
Copy link
Member

I left one final comment, @gabejohnson. Please also rebase your branch. Let me know once you have done so (as I don't receive a notification when you --force push). I'll then merge this pull request. :)

@gabejohnson gabejohnson force-pushed the add-takeWhile-dropWhile branch from 04df4f5 to 951a7e7 Compare March 14, 2017 01:19
@gabejohnson
Copy link
Member Author

@davidchambers It should be good to merge now.

@davidchambers davidchambers merged commit 05f2aa6 into sanctuary-js:master Mar 14, 2017
@gabejohnson gabejohnson deleted the add-takeWhile-dropWhile branch September 19, 2017 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants