scalaz.EphemeralStream.scala Maven / Gradle / Ivy
The newest version!
package scalaz
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicReference
/** Like [[scala.collection.immutable.LazyList]], but doesn't save
* computed values. As such, it can be used to represent similar
* things, but without the space leak problem frequently encountered
* using that type.
*/
sealed abstract class EphemeralStream[A] {
import EphemeralStream._
def isEmpty: Boolean
private[scalaz] def head: () => A
private[scalaz] def tail: () => EphemeralStream[A]
def headOption: Option[A] = {
if(isEmpty) None
else Some(head())
}
def tailOption: Option[EphemeralStream[A]] = {
if(isEmpty) None
else Some(tail())
}
def toList: List[A] =
foldLeft(Nil: List[A])((xs, x) => x :: xs).reverse
def toIList: IList[A] =
foldLeft(INil(): IList[A])((xs, x) => x :: xs).reverse
def foldRight[B](z: => B)(f: (=> A, => B) => B): B =
if (isEmpty) z else f(head(), tail().foldRight(z)(f))
def foldLeft[B](z: B)(f: (B, => A) => B): B = {
@annotation.tailrec
def loop(t: EphemeralStream[A], acc: B): B =
if (t.isEmpty) acc
else loop(t.tail(), f(acc, t.head()))
loop(this, z)
}
def filter(p: A => Boolean): EphemeralStream[A] = {
val rest = this dropWhile (!p(_))
if (rest.isEmpty) emptyEphemeralStream
else cons(rest.head(), rest.tail() filter p)
}
def dropWhile(p: A => Boolean): EphemeralStream[A] = {
var these: EphemeralStream[A] = this
while (!these.isEmpty && p(these.head())) these = these.tail()
these
}
def ++(e: => EphemeralStream[A]): EphemeralStream[A] =
foldRight[EphemeralStream[A]](e)(cons[A])
def flatMap[B](f: A => EphemeralStream[B]): EphemeralStream[B] =
foldRight[EphemeralStream[B]](emptyEphemeralStream)((h, t) => f(h) ++ t)
def map[B](f: A => B): EphemeralStream[B] =
foldRight[EphemeralStream[B]](emptyEphemeralStream)((h, t) => cons(f(h), t))
def length: Int =
foldLeft(0)((c, _) => 1 + c)
def tails: EphemeralStream[EphemeralStream[A]] =
if (isEmpty) EphemeralStream(emptyEphemeralStream)
else cons(this, tail().tails)
def inits: EphemeralStream[EphemeralStream[A]] =
if (isEmpty) EphemeralStream(emptyEphemeralStream)
else cons(emptyEphemeralStream, tail().inits.map(cons(head(), _)))
def findM[M[_]: Monad](p: A => M[Boolean]): M[Option[A]] =
if(isEmpty)
Monad[M].point(None)
else {
val hh = head()
Monad[M].bind(p(hh))(if (_) Monad[M].point(Some(hh)) else tail() findM p)
}
def findMapM[M[_]: Monad, B](f: A => M[Option[B]]): M[Option[B]] = {
if(isEmpty)
Monad[M].point(None)
else{
val hh = head()
Monad[M].bind(f(hh)) { case Some(b) => Monad[M].point(Some(b)); case None => tail() findMapM f }
}
}
def reverse: EphemeralStream[A] = {
foldLeft(emptyEphemeralStream[A])((xs, x) => cons(x, xs))
}
def zip[B](b: => EphemeralStream[B]): EphemeralStream[(A, B)] =
if(isEmpty || b.isEmpty)
emptyEphemeralStream
else
cons((head(), b.head()), tail() zip b.tail())
def unzip[X, Y](implicit ev: A <:< (X, Y)): (EphemeralStream[X], EphemeralStream[Y]) =
foldRight((emptyEphemeralStream[X], emptyEphemeralStream[Y]))((q, r) =>
(cons(q._1, r._1), cons(q._2, r._2)))
def alignWith[B, C](f: A \&/ B => C)(b: EphemeralStream[B]): EphemeralStream[C] =
if(b.isEmpty)
map(x => f(\&/.This(x)))
else if(isEmpty)
b.map(x => f(\&/.That(x)))
else
cons(f(\&/.Both(head(), b.head())), tail().alignWith(f)(b.tail()))
def interleave(q: EphemeralStream[A]): EphemeralStream[A] =
if(isEmpty)
q
else if (q.isEmpty)
this
else
cons(head(), cons(q.head(), tail() interleave q.tail()))
def take(n: Int): EphemeralStream[A] =
unfold((n, this)){ case (len, xs) =>
if(len > 0 && !xs.isEmpty)
Some((xs.head(), (len - 1, xs.tail())))
else
None
}
def takeWhile(p: A => Boolean): EphemeralStream[A] =
if(!isEmpty){
val h = head()
if(p(h)) cons(h, tail().takeWhile(p))
else emptyEphemeralStream
}else this
def zipWithIndex: EphemeralStream[(A, Int)] =
zip(iterate(0)(_ + 1))
def memoized: EphemeralStream[A] =
if (isEmpty) this
else consImpl(weakMemo(head()), weakMemo(tail().memoized))
}
sealed abstract class EphemeralStreamInstances {
implicit val ephemeralStreamIsCovariant: IsCovariant[EphemeralStream] =
IsCovariant.force[EphemeralStream]
// TODO more instances
implicit val ephemeralStreamInstance: MonadPlus[EphemeralStream] & Alt[EphemeralStream] & BindRec[EphemeralStream] & scalaz.Zip[EphemeralStream] & Unzip[EphemeralStream] & Align[EphemeralStream] & Traverse[EphemeralStream] & Cobind[EphemeralStream] & IsEmpty[EphemeralStream] = new MonadPlus[EphemeralStream] with Alt[EphemeralStream] with BindRec[EphemeralStream] with Zip[EphemeralStream] with Unzip[EphemeralStream] with Align[EphemeralStream] with Traverse[EphemeralStream] with Cobind[EphemeralStream] with IsEmpty[EphemeralStream] {
import EphemeralStream._
override def isEmpty[A](fa: EphemeralStream[A]) = fa.isEmpty
override def cojoin[A](a: EphemeralStream[A]): EphemeralStream[EphemeralStream[A]] = a match {
case _ ##:: tl => if (tl.isEmpty) EphemeralStream(a)
else cons(a, cojoin(tl))
case _ => emptyEphemeralStream
}
def cobind[A, B](fa: EphemeralStream[A])(f: EphemeralStream[A] => B): EphemeralStream[B] = map(cojoin(fa))(f)
def plus[A](a: EphemeralStream[A], b: => EphemeralStream[A]) = a ++ b
def alt[A](a: => EphemeralStream[A], b: => EphemeralStream[A]) = plus(a, b)
def bind[A, B](fa: EphemeralStream[A])(f: A => EphemeralStream[B]) = fa flatMap f
def point[A](a: => A) = EphemeralStream(a)
def empty[A] = EphemeralStream()
def zip[A, B](a: => EphemeralStream[A], b: => EphemeralStream[B]) = a zip b
def unzip[A, B](a: EphemeralStream[(A, B)]) = a.unzip
def alignWith[A, B, C](f: A \&/ B => C) =
(a, b) =>
a.alignWith(f)(b)
override def toEphemeralStream[A](fa: EphemeralStream[A]) = fa
override def foldRight[A, B](fa: EphemeralStream[A], z: => B)(f: (A, => B) => B): B =
if(fa.isEmpty) z else f(fa.head(), foldRight(fa.tail(), z)(f))
override def foldMap[A, B](fa: EphemeralStream[A])(f: A => B)(implicit M: Monoid[B]) =
M.unfoldrSum(fa)(as => as.headOption match {
case Some(a) => Maybe.just((f(a), as.tailOption.getOrElse(EphemeralStream())))
case None => Maybe.empty
})
override def foldMap1Opt[A, B](fa: EphemeralStream[A])(f: A => B)(implicit B: Semigroup[B]) =
foldMapRight1Opt(fa)(f)((l, r) => B.append(f(l), r))
override def foldLeft[A, B](fa: EphemeralStream[A], z: B)(f: (B, A) => B) =
fa.foldLeft(z)((b, a) => f(b, a))
override def foldMapRight1Opt[A, B](fa: EphemeralStream[A])(z: A => B)(f: (A, => B) => B): Option[B] = {
def rec(tortoise: EphemeralStream[A], hare: EphemeralStream[A]): B =
if (hare.isEmpty) z(tortoise.head())
else f(tortoise.head(), rec(hare, hare.tail()))
if (fa.isEmpty) None
else Some(rec(fa, fa.tail()))
}
override def foldMapLeft1Opt[A, B](fa: EphemeralStream[A])(z: A => B)(f: (B, A) => B): Option[B] =
if (fa.isEmpty) None
else Some(foldLeft(fa.tail(), z(fa.head()))(f))
override def zipWithL[A, B, C](fa: EphemeralStream[A], fb: EphemeralStream[B])(f: (A, Option[B]) => C) = {
if(fa.isEmpty) emptyEphemeralStream
else {
val (bo, bTail) = if(fb.isEmpty) (None, emptyEphemeralStream[B])
else (Some(fb.head()), fb.tail())
cons(f(fa.head(), bo), zipWithL(fa.tail(), bTail)(f))
}
}
override def zipWithR[A, B, C](fa: EphemeralStream[A], fb: EphemeralStream[B])(f: (Option[A], B) => C) =
zipWithL(fb, fa)((b, a) => f(a, b))
def traverseImpl[F[_], A, B](fa: EphemeralStream[A])(f: A => F[B])(implicit F: Applicative[F]) = {
val revOpt: Maybe[F[List[B]]] =
F.unfoldrOpt[EphemeralStream[A], B, List[B]](fa){
case a ##:: as => Maybe.just((f(a), as))
case emptyEphemeralStream => Maybe.empty
}(Reducer.ReverseListReducer[B])
val rev: F[List[B]] = revOpt getOrElse F.point(Nil)
F.map(rev)((rev) => rev.foldLeft(EphemeralStream[B]())((r, c) => c ##:: r))
}
override def index[A](fa: EphemeralStream[A], i: Int): Option[A] = {
if(i < 0)
None
else{
var n = i
var these = fa
while (!these.isEmpty && n > 0){
n -= 1
these = these.tail()
}
if (these.isEmpty) None else Some(these.head())
}
}
def tailrecM[A, B](a: A)(f: A => EphemeralStream[A \/ B]): EphemeralStream[B] = {
def go(s: EphemeralStream[A \/ B]): EphemeralStream[B] = {
@annotation.tailrec
def rec(abs: EphemeralStream[A \/ B]): EphemeralStream[B] =
abs match {
case \/-(b) ##:: tail => cons(b, go(tail))
case -\/(a0) ##:: tail => rec(f(a0) ++ tail)
case _ => emptyEphemeralStream
}
rec(s)
}
go(f(a))
}
}
import std.list._
implicit def ephemeralStreamEqual[A: Equal]: Equal[EphemeralStream[A]] = Equal[List[A]] contramap {(_: EphemeralStream[A]).toList}
implicit def ephemeralStreamOrder[A](implicit A: Order[A]): Order[EphemeralStream[A]] =
new Order[EphemeralStream[A]] {
import Ordering._
@annotation.tailrec
override final def order(a: EphemeralStream[A], b: EphemeralStream[A]): Ordering =
(a.isEmpty, b.isEmpty) match {
case (true, true) => EQ
case (true, false) => LT
case (false, true) => GT
case _ => A.order(a.headOption.get, b.headOption.get) match {
case EQ => order(a.tailOption.get, b.tailOption.get)
case r => r
}
}
}
implicit def ephemeralStreamMonoid[A]: Monoid[EphemeralStream[A]] =
ephemeralStreamInstance.monoid[A]
implicit def ephemeralStreamShow[A: Show]: Show[EphemeralStream[A]] =
Contravariant[Show].contramap(IList.show[A])(_.toIList)
import Tags.Zip
/**
* An alternative [[scalaz.Applicative]] instance for `EphemeralStream`, discriminated by the type tag [[scalaz.Tags.Zip]],
* that zips streams together.
*
* Example:
* {{{
* import scalaz.Tags.Zip
* streamZipApplicative.apply2(Zip(EphemeralStream(1, 2)), Zip(EphemeralStream(3, 4)))(_ * _) // EphemeralStream(3, 8)
* }}}
*/
implicit val ephemeralStreamZipApplicative: Applicative[λ[α => EphemeralStream[α] @@ Zip]] =
new Applicative[λ[α => EphemeralStream[α] @@ Zip]] {
def point[A](a: => A) = Zip(EphemeralStream.fromLazyList(LazyList.continually(a)))
def ap[A, B](fa: => (EphemeralStream[A] @@ Zip))(f: => (EphemeralStream[A => B] @@ Zip)) = {
Zip(if (Tag.unwrap(f).isEmpty || Tag.unwrap(fa).isEmpty) EphemeralStream.emptyEphemeralStream[B]
else EphemeralStream.cons((Tag.unwrap(f).headOption.get)(Tag.unwrap(fa).headOption.get), Tag.unwrap(ap(Zip(Tag.unwrap(fa).tailOption.get))(Zip(Tag.unwrap(f).tailOption.get)))))
}
}
}
object EphemeralStream extends EphemeralStreamInstances {
type EStream[A] = EphemeralStream[A]
def emptyEphemeralStream[A]: EphemeralStream[A] = new EphemeralStream[A] {
def isEmpty = true
def head: () => Nothing = () => sys.error("head of empty stream")
def tail: () => Nothing = () => sys.error("tail of empty stream")
}
private def consImpl[A](a: () => A, as: () => EphemeralStream[A]) = new EphemeralStream[A] {
def isEmpty = false
val head = a
val tail = as
}
def cons[A](a: => A, as: => EphemeralStream[A]): EphemeralStream[A] =
consImpl(() => a, () => as)
def unfold[A, B](b: => B)(f: B => Option[(A, B)]): EphemeralStream[A] =
f(b) match {
case None => emptyEphemeralStream
case Some((a, r)) => cons(a, unfold(r)(f))
}
def iterate[A](start: A)(f: A => A): EphemeralStream[A] =
unfold(start){ a =>
val fa = f(a)
Some((a, fa))
}
def range(lower: Int, upper: Int): EphemeralStream[Int] =
if (lower >= upper) emptyEphemeralStream else cons(lower, range(lower + 1, upper))
def fromStream[A](s: => Stream[A]): EphemeralStream[A] = s match {
case Stream() => emptyEphemeralStream
case h #:: t => cons(h, fromStream(t))
}
def fromLazyList[A](s: LazyList[A]): EphemeralStream[A] = s match {
case LazyList() => emptyEphemeralStream
case h #:: t => cons(h, fromLazyList(t))
}
def toIterable[A](e: EphemeralStream[A]): Iterable[A] = new scala.collection.AbstractIterable[A] {
def iterator: Iterator[A] = new scala.collection.AbstractIterator[A] {
private[this] var cur = e
def next() = {
val t = cur.head()
cur = cur.tail()
t
}
def hasNext = !cur.isEmpty
}
}
def weakMemo[V](f: => V): () => V = {
val ref: AtomicReference[WeakReference[V]] = new AtomicReference()
() => {
@inline
def genNew(x: V, old: WeakReference[V]): V = {
if (ref.compareAndSet(old, new WeakReference(x)))
x
else {
val crt = ref.get.get
if (crt != null) crt
else x
}
}
val v = ref.get()
if (v != null) {
val crt = v.get()
if (crt == null) {
genNew(f, v)
} else crt
} else genNew(f, v)
}
}
def apply[A]: EphemeralStream[A] =
emptyEphemeralStream
def apply[A](as: A*): EphemeralStream[A] = {
val as0 = as match{
case indexedSeq: scala.collection.IndexedSeq[A] => indexedSeq
case other => other.toIndexedSeq
}
val size = as.size
unfold(0)(b =>
if (b < size) Some((as0(b), b + 1))
else None)
}
class ConsWrap[A](e: => EphemeralStream[A]) {
def ##::(h: A): EphemeralStream[A] = cons(h, e)
}
implicit def consWrapper[A](e: => EphemeralStream[A]): ConsWrap[A] =
new ConsWrap[A](e)
object ##:: {
def unapply[A](xs: EphemeralStream[A]): Option[(A, EphemeralStream[A])] =
if (xs.isEmpty) None
else Some((xs.head(), xs.tail()))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy