Skip to content

Instantly share code, notes, and snippets.

@jdegoes
Created March 17, 2021 20:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdegoes/b69d1d8a3282fab562c88a6d974858ab to your computer and use it in GitHub Desktop.
Save jdegoes/b69d1d8a3282fab562c88a6d974858ab to your computer and use it in GitHub Desktop.
Compositional zipping
package spartans.zipped
object Zipped {
sealed trait Zippable[-A, -B] {
type Out
def zip(left: A, right: B): Out
}
object Zippable extends ZippableLowPriority {
type Out[-A, -B, C] = Zippable[A, B] { type Out = C }
implicit def Zippable3[A, B, Z]: Zippable.Out[(A, B), Z, (A, B, Z)] =
new Zippable[(A, B), Z] {
type Out = (A, B, Z)
def zip(left: (A, B), right: Z): Out = (left._1, left._2, right)
}
implicit def Zippable4[A, B, C, Z]: Zippable.Out[(A, B, C), Z, (A, B, C, Z)] =
new Zippable[(A, B, C), Z] {
type Out = (A, B, C, Z)
def zip(left: (A, B, C), right: Z): Out = (left._1, left._2, left._3, right)
}
implicit def Zippable5[A, B, C, D, Z]: Zippable.Out[(A, B, C, D), Z, (A, B, C, D, Z)] =
new Zippable[(A, B, C, D), Z] {
type Out = (A, B, C, D, Z)
def zip(left: (A, B, C, D), right: Z): Out = (left._1, left._2, left._3, left._4, right)
}
}
trait ZippableLowPriority {
implicit def Zippable2[A, B]: Zippable.Out[A, B, (A, B)] =
new Zippable[A, B] {
type Out = (A, B)
def zip(left: A, right: B): Out = (left, right)
}
}
final case class Task[+A](unsafeRun: () => A) { self =>
def ~[B](that: Task[B])(implicit z: Zippable[A, B]): Task[z.Out] = self zip that
def flatMap[B](f: A => Task[B]): Task[B] = Task(() => f(unsafeRun()).unsafeRun())
def map[B](f: A => B): Task[B] = self.flatMap(a => Task.attempt(f(a)))
def zip[B](that: Task[B])(implicit z: Zippable[A, B]): Task[z.Out] =
self.flatMap(a => that.map(b => z.zip(a, b)))
}
object Task {
def attempt[A](a: => A): Task[A] = Task(() => a)
}
val task: Task[String] = Task.attempt("foo")
val result1: Task[(String, String)] = task.zip(task)
val result2: Task[(String, String, String, String, String)] =
task.zip(task).zip(task).zip(task).zip(task)
def myZip[A, B](t1: Task[A], t2: Task[B]) =
t1.zip(t2)
// (fa |@| fb |@| fc)(f(_, _, _))
// (fa, fb, fc).mapN(f(_, _, _))
// ZIO.mapN(fa, fb, fc)(f(_, _, _))
// Operator to zip / custom extractor
// Custom flatten operator
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment