Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fromFoldable #55

Merged
merged 2 commits into from
Mar 17, 2016
Merged

Add fromFoldable #55

merged 2 commits into from
Mar 17, 2016

Conversation

hdgarrood
Copy link
Contributor

Refs #53. This implementation seems to work, but is not stack-safe (on my machine, on node.js, it fails with >= 5658 elements). Could arrays add a tailrec dependency, maybe?

@garyb
Copy link
Member

garyb commented Jan 15, 2016

If it doesn't cause a circular dependency adding a tailrec dependency sounds good to me 👍

@paf31
Copy link
Contributor

paf31 commented Jan 16, 2016

Sounds good.

@hdgarrood
Copy link
Contributor Author

This one is stack-safe. Unfortunately I couldn't work out how to do it with tailrec. I think I could do it with Trampoline from free but that would be quite a lot slower than this implementation, and would also cause circular dependencies, I think.

@hdgarrood
Copy link
Contributor Author

This now fails because of this code:

exports.sortImpl = function (f) {
  return function (l) {
    /* jshint maxparams: 2 */
    return l.slice().sort(function (x, y) {
      return f(x)(y);
    });
  };
};

Removing the maxparams comment and removing maxparams from .jshintrc fixes it. I think this is probably the right approach, too; I don't think we gain anything from turning it on when we just turn it off again whenever we're required to write an uncurried function, and the tests should be catching any errors anyway.

@paf31
Copy link
Contributor

paf31 commented Feb 27, 2016

👍 LGTM.

@sharkdp
Copy link
Contributor

sharkdp commented Feb 27, 2016

Neat trick 👍

I feel slightly uneasy about passing the effectful _push function to foldl. Is there any guarantee that Foldable instances will call the passed function exactly once for each 'element'? I can break the tests by adding a (admittedly supid) no-op to the Foldable instance for your Replicated type:

instance foldableReplicated :: Foldable Replicated where
  foldr f z (Replicated n x) = applyN n (f x) z
  foldl f z (Replicated n x) = let stupid = f z x
                               in applyN n (flip f x) z
  foldMap = foldMapDefaultR

Apart from that, it looks good to me, too! I'm eagerly awaiting fromFoldable.

@hdgarrood
Copy link
Contributor Author

@sharkdp That's a good point. I was a bit uneasy about this too, but wasn't able to come up with an example that broke things. Maybe a better implementation would be something (conceptually) similar to foldr Cons Nil >>> listToArray then.

@hdgarrood
Copy link
Contributor Author

This new implementation has what I would deem acceptable performance, ~100ms to run fromFoldable (replicate 100000 'a') on my machine. If people are worried about performance then they can use a more specialized alternative, anyway.

@hdgarrood
Copy link
Contributor Author

Ok I actually benchmarked it instead of guessing from-foldable

@sharkdp
Copy link
Contributor

sharkdp commented Feb 27, 2016

Looks good 👍.

Concerning the benchmark, a comparison to the _push implementation would be interesting.

@hdgarrood
Copy link
Contributor Author

Good idea. As usual, my intuition was wrong:
from-foldable 2

@hdgarrood
Copy link
Contributor Author

(I was expecting the stateful one to be quite a lot faster.)

@sharkdp
Copy link
Contributor

sharkdp commented Feb 27, 2016

Cool, thanks! I also expected a bigger difference..

@hdgarrood
Copy link
Contributor Author

Unfortunately my tool is not very good at labeling the axes... but it looks like it is quite a lot faster for smaller arrays (<100,000 elements), at least. Anyway I'm fairly certain the viaList one is the right approach now.

@hdgarrood
Copy link
Contributor Author

I've just squashed the commits, so the stateful implementation is gone now, but for anyone looking at this in the future, it was:

foreign import fromFoldableImpl :: forall f a.
  (forall b. (b -> a -> b) -> b -> f a -> b) -> f a -> Array a

fromFoldable :: forall f a. (Foldable f) => f a -> Array a
fromFoldable = fromFoldableImpl foldl
exports.fromFoldableImpl = function (foldl) {
  return function (xs) {
    var result = [];
    var push = function (x) { result.push(x); };
    var push_ = function () { return push; };
    foldl(push_)(null)(xs);
    return result;
  };
};

@garyb
Copy link
Member

garyb commented Feb 27, 2016

Last I knew using result.push was significantly slower than doing something like result[count++] = x, so that might have helped.

@ethul
Copy link
Contributor

ethul commented Feb 28, 2016

@garyb
Copy link
Member

garyb commented Mar 16, 2016

@hdgarrood could you rebase on the latest master please?

@hdgarrood hdgarrood force-pushed the from-foldable branch 2 times, most recently from 5c98481 to 22369a5 Compare March 16, 2016 14:16
@tthdgarrood
Copy link

Done.

This should speed it up. I might do a proper benchmark (once the core
libraries are all updated).
@garyb
Copy link
Member

garyb commented Mar 17, 2016

Thanks!

garyb added a commit that referenced this pull request Mar 17, 2016
@garyb garyb merged commit dd9b949 into purescript:master Mar 17, 2016
@hdgarrood hdgarrood deleted the from-foldable branch March 18, 2016 00:36
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.

6 participants