-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
More efficient slidingN functions #4067
Conversation
We piggy-back on `toIterable`. This is also an easy way to avoid stack overflow.
Can we add the example from #4066 as a test? |
Where should I add this? |
Aside question: how come I mean, if |
There is no methods to create an |
I approved, but I do think adding the test that caused a stack overflow would be good. |
I'm just thinking – wouldn't This is a question for the future of course – not related to this PR specifically. |
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.
Thanks for the quick fix :)
Co-authored-by: Arman Bilge <armanbilge@gmail.com>
@satorg I don't see a function like this in cats, but I think we could add it: trait Alternative[F[_]] ... {
def fromFoldable[G[_], A](ga: G[A])(implicit G: Foldable[G]): F[A] = {
@tailrec def loop(lst: List[A], left: F[A]): F[A] =
lst match {
case a :: as => appendK(left, a)
case Nil => left
}
loop(G.toList(ga), empty)
}
} which we could override with more efficient implementations as needed (such as going in the reverse direction for building list, or using a List.newBuilder). |
@johnynek what I really meant is that having both def slidingN[F[_]: Alternative : Foldable, A](fa: F[A]): F[(A, ..., A)] while preserving laziness for those What I was thinking about – there's def lazySliding3[F[_], A](fa: F[A])(implicit FA: Alternative[F], FF: Foldable[F], FM: FlatMap[F]): F[(A, A, A)] = {
val it =
FF.toIterable(fa).iterator.sliding(3).withPartial(false)
.map(_.toList).map { case a1 :: a2 :: a3 :: Nil => (a1, a2, a3) }
def go(): F[(A, A, A)] = {
FA
.pure(Eval.later {
if (it.hasNext)
FA.prependK(it.next(), go())
else
FA.empty[(A, A, A)]
})
.flatMap(_.value) // this trick shifts all prependK into "lazy" context for lazy collections
}
go()
} Note: this is a "quick and dirty" implementation. It is not stack-safe for non-lazy collections. |
The issue with I am not really sure it is the issue though – maybe it is an expected behavior ) |
We piggy-back on
toIterable
.This is also an easy way to avoid stack overflow.
Fixes #4066