Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion core/src/main/scala/decrel/reify/bifunctor/proof.scala
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ trait proof { this: access & reifiedRelation =>
LeftOut,
LeftOutRefined <: LeftOut,
RightTree,
RightIn <: LeftIn,
RightIn,
RightE,
RightOut,
ZippedOut,
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/decrel/reify/monofunctor/proof.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ trait proof { this: access & reifiedRelation =>
LeftOut,
LeftOutRefined <: LeftOut,
RightTree,
RightIn <: LeftIn,
RightIn,
RightOut,
ZippedOut,
ZOR <: ZippedOut
Expand Down
16 changes: 8 additions & 8 deletions core/src/main/scala/decrel/syntax.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,23 @@ trait syntax {
)(implicit
ev: LeftOut <:< RightIn,
zippable: Zippable.Out[LeftOut, RightOut, ZippedOut]
): Relation.Composed.Zipped[
): Composed.Single[
LeftTree & Relation.Single[LeftIn, LeftOut],
LeftIn,
LeftOut,
Relation.Composed.Single[
LeftTree & Relation.Single[LeftIn, LeftOut],
LeftIn,
Composed.Zipped[
Relation.Self[LeftOut],
LeftOut,
LeftOut,
RightTree & Relation[RightIn, RightOut],
RightIn,
Comment on lines +42 to 46
RightOut
RightOut,
ZippedOut
],
LeftIn,
RightOut,
LeftOut,
ZippedOut
] =
Relation.Composed.Zipped(left, Relation.Composed.Single(left, right))
Relation.Composed.Single(left, Relation.Composed.Zipped(Relation.Self[LeftOut], right))

def >>:[LeftTree, LeftIn, LeftOut](
left: LeftTree & Relation.Optional[LeftIn, LeftOut]
Expand Down
100 changes: 4 additions & 96 deletions core/src/test/scala/decrel/RelationSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,7 @@ object RelationSpec extends ZIOSpecDefault {
assertCompletes
},
test("one to one, zipped") {
val composed: Composed.Zipped[
Foo.bar.type & Relation.Single[Foo, Bar],
Foo, // Input
Bar,
Composed.Single[
Foo.bar.type & Relation.Single[Foo, Bar],
Foo,
Bar,
Bar.baz.type & Relation.Single[Bar, Baz],
Bar,
Baz
],
Foo,
Baz,
(Bar, Baz) // Output
] =
Foo.bar <>: Bar.baz
val composed = Foo.bar <>: Bar.baz

val _: Relation[Foo, (Bar, Baz)] = composed

Expand Down Expand Up @@ -223,69 +207,15 @@ object RelationSpec extends ZIOSpecDefault {
assertCompletes
},
test("compose one zipped & a zipped relation") {
val composed: Composed.Zipped[
Foo.baz.type & Relation.Single[Foo, Baz],
Foo,
Baz,
Composed.Single[
Foo.baz.type & Relation.Single[Foo, Baz],
Foo,
Baz,
Composed.Zipped[
Baz.foo.type & Relation[Baz, Option[Foo]],
Baz,
Option[Foo],
Baz.bar.type & Relation[Baz, Option[Bar]],
Baz,
Option[Bar],
(Option[Foo], Option[Bar])
] & Relation[Baz, (Option[Foo], Option[Bar])],
Baz,
(Option[Foo], Option[Bar])
],
Foo,
(Option[Foo], Option[Bar]),
(Baz, Option[Foo], Option[Bar])
] =
val composed =
Foo.baz <>: (Baz.foo & Baz.bar)

val _: Relation[Foo, (Baz, Option[Foo], Option[Bar])] = composed

assertCompletes
},
test("compose one compose one zipped & a zipped relation") {
val composed: Composed.Zipped[
Foo.self.type & Relation[Foo, Foo],
Foo,
Foo,
Composed.Zipped[
Foo.baz.type & Relation.Single[Foo, Baz],
Foo,
Baz,
Composed.Single[
Foo.baz.type & Relation.Single[Foo, Baz],
Foo,
Baz,
Composed.Zipped[
Baz.foo.type & Relation[Baz, Option[Foo]],
Baz,
Option[Foo],
Baz.bar.type & Relation[Baz, Option[Bar]],
Baz,
Option[Bar],
(Option[Foo], Option[Bar])
] & Relation[Baz, (Option[Foo], Option[Bar])],
Baz,
(Option[Foo], Option[Bar])
],
Foo,
(Option[Foo], Option[Bar]),
(Baz, Option[Foo], Option[Bar])
] & Relation[Foo, (Baz, Option[Foo], Option[Bar])],
Foo,
(Baz, Option[Foo], Option[Bar]),
(Foo, Baz, Option[Foo], Option[Bar])
] =
val composed =
Foo.self & (Foo.baz <>: (Baz.foo & Baz.bar))

val _: Relation[Foo, (Foo, Baz, Option[Foo], Option[Bar])] = composed
Expand Down Expand Up @@ -484,29 +414,7 @@ object RelationSpec extends ZIOSpecDefault {
assertCompletes
},
test("<>: and >>: has same operator precedence") {
val composed: Composed.Zipped[
Foo.bar.type & Relation.Single[Foo, Bar],
Foo,
Bar,
Composed.Single[
Foo.bar.type & Relation.Single[Foo, Bar],
Foo,
Bar,
Composed.Single[
Bar.baz.type & Relation.Single[Bar, Baz],
Bar,
Baz,
Baz.foo.type & Relation[Baz, Option[Foo]],
Baz,
Option[Foo]
] & Relation[Bar, Option[Foo]],
Bar,
Option[Foo]
],
Foo,
Option[Foo],
(Bar, Option[Foo])
] =
val composed =
Foo.bar <>: Bar.baz >>: Baz.foo

val _: Relation[Foo, (Bar, Option[Foo])] = composed
Expand Down
74 changes: 74 additions & 0 deletions core/src/test/scala/decrel/reify/bifunctor/KeepCoherenceSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package decrel.reify.bifunctor

import decrel.*
import zio.test.*

object KeepCoherenceSpec extends ZIOSpecDefault {
object next extends Relation.Single[Int, Int]
object doubled extends Relation.Single[Int, Int]

object described extends Relation.Single[AnyVal, String]

class Interpreter extends access with proof with reifiedRelation {
type Access[+E, +A] = () => A
protected def succeed[A](a: A): Access[Nothing, A] = () => a
protected def flatMap[E, A, B](a: Access[E, A])(f: A => Access[E, B]): Access[E, B] = () =>
f(a())()
protected def map[E, A, B](a: Access[E, A])(f: A => B): Access[E, B] = () => f(a())

implicit val describedProof: Proof.Single[described.type, AnyVal, Nothing, String] =
new Proof.Single[described.type, AnyVal, Nothing, String] {
val reify: ReifiedRelation[AnyVal, Nothing, String] =
new ReifiedRelation.FromFunction[AnyVal, String](_.toString)
}

var calls = 0
type Id[A] = A
def relation(f: Int => Int): ReifiedRelation[Int, Nothing, Int] =
new ReifiedRelation.Transformed[Int, Id, Nothing, Id, Int](
new ReifiedRelation.FromFunction[Int, Int](identity),
f
)
implicit val nextProof: Proof.Single[next.type, Int, Nothing, Int] =
new Proof.Single[next.type, Int, Nothing, Int] {
val reify = relation { _ => calls += 1; calls }
}
implicit val doubledProof: Proof.Single[doubled.type, Int, Nothing, Int] =
new Proof.Single[doubled.type, Int, Nothing, Int] {
val reify = relation(_ * 2)
}
}

private def checked(label: String)(assertion: => TestResult) =
test(label)(Live.live(zio.ZIO.sleep(zio.Duration.fromMillis(10))) *> zio.ZIO.attempt(assertion))

def spec: Spec[Environment, Any] = suite("retained single coherence")(
checked("retained values can feed a strict supertype input") {
val interpreter = new Interpreter
import interpreter.*
val composed = next <>: described
val reified = composed.reify
val single = reified.apply(0)()
val bulk = reified.applyMultiple(Vector(0, 0))()
assertTrue(single == (1, "1"), bulk == Vector((2, "2"), (3, "3")), calls == 3)
},
checked("retain exactly the value consumed downstream, once per execution") {
val interpreter = new Interpreter
import interpreter.*
val composed = next <>: doubled
val reified: ReifiedRelation[Int, Nothing, (Int, Int)] = composed.reify
val run = reified.apply(0)
val first = run()
val second = run()
assertTrue(first == (1, 2), second == (2, 4), calls == 2)
},
checked("bulk execution retains each corresponding downstream input") {
val interpreter = new Interpreter
import interpreter.*
val composed = next <>: doubled
val reified: ReifiedRelation[Int, Nothing, (Int, Int)] = composed.reify
val result = reified.applyMultiple(Vector(0, 0, 0))()
assertTrue(result == Vector((1, 2), (2, 4), (3, 6)), calls == 3)
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package decrel.reify.monofunctor

import decrel.*
import zio.test.*

object KeepCoherenceSpec extends ZIOSpecDefault {
object next extends Relation.Single[Int, Int]
object doubled extends Relation.Single[Int, Int]

object described extends Relation.Single[AnyVal, String]

class Interpreter extends access with proof with reifiedRelation {
type Access[A] = () => A
protected def succeed[A](a: A): Access[A] = () => a
protected def flatMap[A, B](a: Access[A])(f: A => Access[B]): Access[B] = () => f(a())()
protected def map[A, B](a: Access[A])(f: A => B): Access[B] = () => f(a())

implicit val describedProof: Proof.Single[described.type, AnyVal, String] =
new Proof.Single[described.type, AnyVal, String] {
val reify: ReifiedRelation[AnyVal, String] =
new ReifiedRelation.FromFunction[AnyVal, String](_.toString)
}

var calls = 0
type Id[A] = A
def relation(f: Int => Int): ReifiedRelation[Int, Int] =
new ReifiedRelation.Transformed[Int, Id, Id, Int](
new ReifiedRelation.FromFunction[Int, Int](identity),
f
)
implicit val nextProof: Proof.Single[next.type, Int, Int] =
new Proof.Single[next.type, Int, Int] {
val reify = relation { _ => calls += 1; calls }
}
implicit val doubledProof: Proof.Single[doubled.type, Int, Int] =
new Proof.Single[doubled.type, Int, Int] {
val reify = relation(_ * 2)
}
}

private def checked(label: String)(assertion: => TestResult) =
test(label)(Live.live(zio.ZIO.sleep(zio.Duration.fromMillis(10))) *> zio.ZIO.attempt(assertion))

def spec: Spec[Environment, Any] = suite("retained single coherence")(
checked("retained values can feed a strict supertype input") {
val interpreter = new Interpreter
import interpreter.*
val composed = next <>: described
val reified = composed.reify
val single = reified.apply(0)()
val bulk = reified.applyMultiple(Vector(0, 0))()
assertTrue(single == (1, "1"), bulk == Vector((2, "2"), (3, "3")), calls == 3)
},
checked("retain exactly the value consumed downstream, once per execution") {
val interpreter = new Interpreter
import interpreter.*
val composed = next <>: doubled
val reified: ReifiedRelation[Int, (Int, Int)] = composed.reify
val run = reified.apply(0)
val first = run()
val second = run()
assertTrue(first == (1, 2), second == (2, 4), calls == 2)
},
checked("bulk execution retains each corresponding downstream input") {
val interpreter = new Interpreter
import interpreter.*
val composed = next <>: doubled
val reified: ReifiedRelation[Int, (Int, Int)] = composed.reify
val result = reified.applyMultiple(Vector(0, 0, 0))()
assertTrue(result == Vector((1, 2), (2, 4), (3, 6)), calls == 3)
}
)
}
Loading