-
Notifications
You must be signed in to change notification settings - Fork 21
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
Iterator.unfold is missing #10955
Comments
Yes! Corollary: can we have |
@LPTK do you think |
@NthPortal you made me check, and I was surprised to see that |
import scala.collection.AbstractIterator
object Laziness extends App {
def unfoldIterator[A, S](init: S)(f: S => Option[(A, S)]): Iterator[A] = {
var currentState = init
var nextResultAndState: Option[(A, S)] = null
new AbstractIterator[A] {
override def hasNext: Boolean = {
if (nextResultAndState == null) {
nextResultAndState = f(currentState)
}
nextResultAndState.isDefined
}
override def next(): A = {
assert(hasNext)
val (result, state) = nextResultAndState.get
currentState = state
nextResultAndState = null
result
}
}
}
val lazyList1 = LazyList.unfold(5) { _ =>
println("lazy list generator invoked")
None
}
val iterator = unfoldIterator(5) { _ =>
println("iterator generator invoked")
None
}
println("before converting")
val lazyList2 = iterator.to(LazyList)
println("after converting")
lazyList2.headOption
println("after inspecting")
} Probably unfolding LazyList and creating LazyList from Iterator needs some additional lazy wrappers. OTOH, Iterator based unfold could be used to implement unfold for all collections. See this: import scala.collection.immutable.WrappedString
import scala.collection.{AbstractIterator, Factory, IterableFactory}
import scala.language.higherKinds
object UnfoldOps extends App {
implicit class CollectionUnfoldOps1[A, C](factory: Factory[A, C]) {
def unfold[S](init: S)(f: S => Option[(A, S)]): C =
factory.fromSpecific(unfoldIterator(init)(f))
}
implicit class CollectionUnfoldOps2[C[_]](factory: IterableFactory[C]) {
def unfold[A, S](init: S)(f: S => Option[(A, S)]): C[A] =
factory.fromSpecific(unfoldIterator(init)(f))
}
def unfoldIterator[A, S](init: S)(f: S => Option[(A, S)]): Iterator[A] = {
var currentState = init
var nextResultAndState: Option[(A, S)] = null
new AbstractIterator[A] {
override def hasNext: Boolean = {
if (nextResultAndState == null) {
nextResultAndState = f(currentState)
}
nextResultAndState.isDefined
}
override def next(): A = {
assert(hasNext)
val (result, state) = nextResultAndState.get
currentState = state
nextResultAndState = null
result
}
}
}
val initialState = 5
val generator = (state: Int) =>
if (state < 10) Some((state.toChar, state + 1)) else None
LazyList.unfold(initialState)(generator)
Vector.unfold(initialState)(generator)
WrappedString.unfold(initialState)(generator)
Iterable.unfold(initialState)(generator)
} Both code examples are for Scala 2.13.0-M4 Update: def lazierUnfold[A, S](init: => S)(f: S => Option[(A, S)]): LazyList[A] =
LazyList.unfold(() => init)(ff => f(ff()).map(p => (p._1, () => p._2))) Someone could want to go deeper and demand signature like: def laziestUnfold[A, S](init: => S)(f: S => Option[(A, => S)]): LazyList[A] which could be implemented similarly. |
See this post for a motivation: https://contributors.scala-lang.org/t/which-operations-should-be-included-in-the-new-collections/1106/75
In short:
LazyList
has ununfold
but since it memoizes its elements it’s not memory efficient. We should either implement it in a GC-friendly way or simply addunfold
to theIterator
companion.The text was updated successfully, but these errors were encountered: