-
Notifications
You must be signed in to change notification settings - Fork 71
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
added sliding-window functions sliding and slidingWithSizeAndStep #212
Conversation
Hi maintainers! |
Just a few initial thoughts about this:
|
Hi Jordan! I started using purescript around one month ago and I love your great website with all the examples. Used it a lot while getting familiar with the language and it helped me a lot. 👍 Thanks for your comprehensive input on the PR. tl;dr Here's my plan - what do you think?
I think the runtime of a list-implementation would be quite horrible due to the lack of index-lookups - if the windows overlap. In that case it could be faster to copy the list into an array, perform the function and convert the result back to a list. So +1 for waiting until people ask for it. ;-)
I never heard of STFn. Do you mean this? https://github.com/purescript/purescript-st I also can't judge that part, since I'm new to purescript.
I use
Good to know, I like the idea. Is it ok to use a record to give the parameters names? Or is currying more common in purescript?
Great idea. Haven't thought about that. |
I think we should avoid FFI in core because of portability - it should ideally not be any harder than it needs to be to get the core libraries running on a new backend. I also prefer |
Glad to hear it helped!
I think what you have is good (i.e. currying). While it does make it harder to understand which argument is which, the alternatives aren't much better. Below are a few examples that highlight their problems:
Yeah, terrible performance would likely cause us to go in that direction (i.e. transforming to an array first, sliding, and transforming back to a list).
That's what the discussion around purescript/purescript-st#31 involves (though there is more to it than just that). If that idea was implemented, we would get something as (nearly?) fast as FFI, but without the backend portability issues that Harry mentioned. However, this idea is more nuanced than what I'm summarizing here, so it's not just an "obvious" fix that we haven't yet implemented. Because
Also, because I don't think I was clear earlier, I agree with Harry on this point. Someone who really wants the same thing in a very performant way could write the FFI for their specific project.
I agree with this on principle, but I'd still like to see if we could make the name shorter. If we dropped with |
Thanks for your input, @JordanMartinez and @hdgarrood. I really appreciate it. Always a pleasure when the first contact with the community of a programming language is positive. I'm going to measure the current implementation and come up with improvements probably on the weekend and get back to you with results. Currently running a bit low on energy after work, since I have allergies and my archenemy (birch tree) is in full bloom. |
Sounds good! |
It took me a while to figure out how to use I skipped the measurement-part of the implementation, since it now operates on a mutable array and avoids copying and I didn't want to open another rabbit hole tbh ;-) Still at the stage in my learning curve where I struggle with the syntax from time to time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good. Just need to clean up a few docs and some of the code.
Thanks again for your input, @JordanMartinez and @hdgarrood. Made the documentation much clearer imo. |
4994b9f
to
25dd1cd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll let other core team members weigh in on this PR.
One minor change that could also be done is to replace void $
with _ <-
. Not sure how much of a difference it makes. For example, in rangeWithStep'
arr <- STA.new
-- Original
-- void $ helper start arr
-- Updated
_ <- helper start arr
pure arr
src/Data/Array.purs
Outdated
then [] | ||
else STA.run | ||
( do | ||
let |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a stylistic change. The parenthesis after the ST.run
can be removed if you follow it with do
else ST.run do
let
helper current acc = {- code... -}
arr <- STA.new
Just to clarify, normally ST.run $ codeBlock
will work. However, because of the Rank-2 type in ST.run
(i.e. the h
type parameter), using $
in this way will always produce a compiler error. However, using do
creates a new block, so the parenthesis are no longer needed.
Other than that, I think this is ready to merge
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I found that out the hard way when I tried to move the helper function out of the ST.run block. Never heard about rank-2 types before - at least not consciously ;-)
The build failed because of an unused variable, but I haven't touched that place in the code. 🤔 |
PureScript 0.14.1 was released yesterday and we have CI on core libraries run on the latest compiler. The build is failing because of a newly-introduced warning. It's fixed by #213, so once that merges your build will be fixed as well. |
You can merge the default branch to fix the build now. Thanks! |
Thanks, @thomashoneyman, worked like a charm! |
Sorry that I didn't raise this sooner, but I am actually a bit hesitant to merge this at this moment in time. We ought to be really careful about adding things to the core libraries, because if we don't get the APIs for functions right the first time, it means we need to make breaking changes to fix them, and breaking changes in libraries that the overwhelming majority of the ecosystem depends on are much more painful than breaking changes that only a small section of the ecosystem depends on. In practice, I've found that it's almost impossible to get APIs right the first time, especially if we have not considered a variety of situations where the API might be useful to have. Making sure the core libraries continue to improve and don't stagnate at the same time as avoiding unnecessary breakage and ecosystem churn is a very delicate balancing act. I'll suggest some rules of thumb for when something should be added to the core libraries based on my experience:
For an example of the last point - as I recall, the last time I wanted a sliding view over an array, I wanted something more like this:
where Another reason to be wary about adding things to the core libraries is that it adds more of a maintenance burden on the core team. This is why I am often in favour of letting APIs be trialled in third party packages first - it is much easier to iterate on the design when the API lives in a separate package (because breaking changes can be made much more frequently), and it's also easier to provide evidence that the API is in demand if we see other packages start to depend on it. (as an aside: I think it might be nice to adopt a system like Rust's stability annotations which would make it much easier to iterate on things within the core libraries without introducing too much ecosystem churn, but that's probably quite a big project.) I'm not saying we shouldn't merge this, I just think we should consider these points a bit more carefully before merging. I personally think I am spreading myself a bit too thin, and I'd like to focus more on the language and compiler, so in this specific case I am going to step back and let others in the core team decide (and I'll be happy with whatever your decision is). |
@hdgarrood Good thoughts!
This sounds like a larger discussion to be had somewhere outside of this repo. I'll open an issue in the
Hmm... The Zipper-like design you propose seems similar to the approach I took when writing purescript-arrays-zipper. But it seems like your approach is more flexible in that the resulting zipper could focus one element at a time or focus one window as done in this PR at a time.
Thanks! I think the direction I would like to take here is to continue with what you proposed, however, and think through this design more. In other words, I think it would make more sense to open a new issue on this repo, talk about the problem these functions try to solve, the various ways they could be designed, which approach makes the most sense, and whether that approach should exist as a separate library or be merged into here. |
@FloWi I'm going to open an issue where we can discuss the design of this idea more. I'll backlink to this PR in the issue. |
Can this be merged? |
@JordanMartinez can we merge this? I think it is better to have it than not and it implements a well established function that is also part of the standard libs in other programming languages, like e.g. Scala https://www.scala-lang.org/api/3.1.2/scala/collection/immutable/IndexedSeq.html#sliding-fffff156 |
@sigma-andex Did you look at the discussion in #214? Could you continue the conversation there? |
Added the functions sliding and slidingWithSizeAndStep to allow sliding-window computations. In order to realise the slidingWithSizeAndStep I added rangeWithStep.
I decided to have the functions return empty arrays in case the user gave them nonsensical arguments. Can change that to Maybe if that's preferred.
Thanks for the review, @sigma-andex.