Skip to content

Instantly share code, notes, and snippets.

@ASRagab
Created February 18, 2019 20:05
Show Gist options
  • Save ASRagab/59e2b583dead1579fe07b274e8ada8ba to your computer and use it in GitHub Desktop.
Save ASRagab/59e2b583dead1579fe07b274e8ada8ba to your computer and use it in GitHub Desktop.
StreamZipper with Comonad Instance
import cats._
import cats.implicits._
case class StreamZipper[A](left: Stream[A], focus: A, right: Stream[A]) {
def moveLeft: StreamZipper[A] =
if (left.isEmpty) this
else new StreamZipper[A](left.tail, left.head, focus #:: right)
def moveRight: StreamZipper[A] =
if (right.isEmpty) this
else new StreamZipper[A](focus #:: left, right.head, right.tail)
private lazy val lefts: Stream[StreamZipper[A]] = Stream.iterate(this)(_.moveLeft).tail.zip(left).map(_._1)
private lazy val rights: Stream[StreamZipper[A]] = Stream.iterate(this)(_.moveRight).tail.zip(right).map(_._1)
lazy val cojoin = new StreamZipper(lefts, this, rights)
def toList: List[A] = left.toList.reverse ++ List(focus) ++ right.toList
def toIterable: Iterable[A] = left.reverse ++ Iterable(focus) ++ right
}
object StreamZipper {
def apply[A](left: List[A], focus: A, right: List[A]): StreamZipper[A] = new StreamZipper(left.reverse
.toStream, focus, right.toStream)
def apply[A](ls: Seq[A]): StreamZipper[A] = new StreamZipper(Stream.empty[A], ls.head, ls.tail.toStream)
implicit object ZipperCoMonad extends Comonad[StreamZipper] {
override def extract[A](x: StreamZipper[A]): A = x.focus
override def coflatMap[A, B](fa: StreamZipper[A])(f: StreamZipper[A] => B): StreamZipper[B] =
map(fa.cojoin)(f)
override def map[A, B](fa: StreamZipper[A])(f: A => B): StreamZipper[B] =
new StreamZipper(fa.left.map(f), f(fa.focus), fa.right.map(f))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment