Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kyo

import kyo.debug.Debug
import kyo.internal.Zippable
import kyo.kernel.ArrowEffect
import scala.annotation.tailrec
import scala.annotation.targetName
Expand Down Expand Up @@ -96,14 +97,15 @@ extension [A, E, Ctx](effect: A < (Abort[E] & Async & Ctx))
using
r: Reducible[Abort[E]],
r1: Reducible[Abort[E1]],
fr: Frame
): (A, A1) < (r.SReduced & r1.SReduced & Async & Ctx & Ctx1) =
fr: Frame,
zippable: Zippable[A, A1]
): zippable.Out < (r.SReduced & r1.SReduced & Async & Ctx & Ctx1) =
for
fiberA <- Fiber.run(using s)(effect)
fiberA1 <- Fiber.run(using s2)(next)
a <- fiberA.join
a1 <- fiberA1.join
yield (a, a1)
yield zippable.zip(a, a1)

end extension

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kyo

import kyo.Result.Error
import kyo.debug.Debug
import kyo.internal.Zippable
import kyo.kernel.ArrowEffect
import scala.annotation.tailrec
import scala.annotation.targetName
Expand Down Expand Up @@ -42,8 +43,8 @@ extension [A, S](effect: A < S)
* A computation that produces a tuple of both results
*/
@targetName("zip")
def <*>[A1, S1](next: => A1 < S1)(using Frame): (A, A1) < (S & S1) =
effect.map(e => next.map(n => (e, n)))
def <*>[A1, S1](next: => A1 < S1)(using frame: Frame, zippable: Zippable[A, A1]): zippable.Out < (S & S1) =
effect.map(e => next.map(n => zippable.zip(e, n)))

/** Performs this computation and prints its result to the console.
*
Expand Down
23 changes: 23 additions & 0 deletions kyo-combinators/shared/src/main/scala/kyo/internal/Zippable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package kyo.internal

trait Zippable[-A, -B]:
type Out
def zip(left: A, right: B): Out

object Zippable extends ZippableLowPrio0:

given left[A]: (Zippable[A, Unit] { type Out = A }) = (left: A, _) => left
given right[B]: (Zippable[Unit, B] { type Out = B }) = (_, right: B) => right

given concat[A <: Tuple, B <: Tuple]: (Zippable[A, B] { type Out = Tuple.Concat[A, B] }) = (left: A, right: B) => left ++ right

def apply[A, B](using z: Zippable[A, B]): Zippable[A, B] = z

def zip[A, B](a: A, b: B)(using z: Zippable[A, B]): z.Out = z.zip(a, b)
end Zippable

trait ZippableLowPrio0 extends ZippableLowPrio1:
given append[A <: Tuple, B]: (Zippable[A, B] { type Out = Tuple.Append[A, B] }) = (left: A, right: B) => left :* right

trait ZippableLowPrio1:
given pair[A, B]: (Zippable[A, B] { type Out = (A, B) }) = (left: A, right: B) => (left, right)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package kyo.internal

import kyo.*
import org.scalatest.compatible.Assertion

class ZippableTest extends Test:
"compile" - {
def check[A, B](using zip: Zippable[A, B])[Expected](using (zip.Out =:= Expected)): Assertion = succeed

def on[A, B, C, D]: Assertion =
check[(A, B), (C, D)][(A, B, C, D)]
check[Unit, A][A]
check[Unit, B][B]
check[(A, B), Unit][(A, B)]
check[(A, B), C][(A, B, C)]
end on

}

"zip" in {
assert(Zippable.zip(1, 2) == (1, 2))
assert(Zippable.zip(1, ()) == 1)
assert(Zippable.zip((), 2) == 2)
assert(Zippable.zip((1, 2), 3) == (1, 2, 3))
assert(Zippable.zip((1, 2), ()) == (1, 2))
assert(Zippable.zip((), (3, 4)) == (3, 4))
assert(Zippable.zip((1, 2), (3, 4)) == (1, 2, 3, 4))
}

"prepend" in {
assert(Zippable.zip(2, (3, 4)) == (2, (3, 4)))
}
end ZippableTest
Loading