From aa6ea6bba2c525784500262ea9c00654aa8b4e29 Mon Sep 17 00:00:00 2001 From: satorg Date: Fri, 12 Jul 2024 01:05:14 -0700 Subject: [PATCH 1/3] add code generator for Gen.zipWith --- project/codegen.scala | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/project/codegen.scala b/project/codegen.scala index 04d52922..d73053ac 100644 --- a/project/codegen.scala +++ b/project/codegen.scala @@ -37,6 +37,13 @@ object codegen { s"$g.flatMap(($t: $T) => $acc)" } + def flatMappedGeneratorsWithFun(i: Int, f: String, s: Seq[(String, String)]): String = + s.init.foldRight(s"${s.last._2}.map { ${s.last._1} => $f(${vals(i)}) }") { + case ((t, g), acc) => + val T = t.toUpperCase + s"$g.flatMap(($t: $T) => $acc)" + } + def vals(i: Int) = csv(idents("t", i)) def coImplicits(i: Int) = (1 to i).map(n => s"co$n: Cogen[T$n]").mkString(",") @@ -106,6 +113,20 @@ object codegen { |""".stripMargin } + def zipWith(i: Int) = { + val gens = flatMappedGeneratorsWithFun(i, "f", idents("t", i) zip idents("g", i)) + s""" + | /** Combines the given generators into a new generator of the given result type + | * with help of the given mapping function. */ + | def zipWith[${types(i)},R]( + | ${wrappedArgs("Gen", i)} + | )( + | f: (${types(i)}) => R + | ): Gen[R] = + | $gens + |""".stripMargin + } + def resultOf(i: Int) = { def delegate = idents("T", i).drop(1).map("_:" + _).mkString(",") s""" @@ -196,6 +217,9 @@ object codegen { | // zip // |${1 to 22 map zip mkString ""} | + | // zipWith // + |${(2 to 22).map(zipWith).mkString("")} + | | // resultOf // | import Arbitrary.arbitrary | def resultOf[T,R](f: T => R)(implicit a: Arbitrary[T]): Gen[R] From 9bce4597113d71fa0e14b42d78468e2dfdc667d4 Mon Sep 17 00:00:00 2001 From: satorg Date: Fri, 12 Jul 2024 01:05:20 -0700 Subject: [PATCH 2/3] add tests --- .../org/scalacheck/GenSpecification.scala | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/core/jvm/src/test/scala/org/scalacheck/GenSpecification.scala b/core/jvm/src/test/scala/org/scalacheck/GenSpecification.scala index 341ff264..7f10798f 100644 --- a/core/jvm/src/test/scala/org/scalacheck/GenSpecification.scala +++ b/core/jvm/src/test/scala/org/scalacheck/GenSpecification.scala @@ -492,6 +492,41 @@ object GenSpecification extends Properties("Gen") with GenSpecificationVersionSp _ == ((1, 2, 3, 4, 5, 6, 7, 8, 9)) } + property("zipWith2") = { + val ts = (1.toShort, 2.toInt) + def fun(t1: Short, t2: Int) = (t1, t2) + + forAll(zipWith(const(ts._1), const(ts._2))(fun)) { + _ == ts + } + } + property("zipWith3") = { + val ts = (1.toShort, 2.toInt, 3.toLong) + def fun(t1: Short, t2: Int, t3: Long) = (t1, t2, t3) + + forAll(zipWith(const(ts._1), const(ts._2), const(ts._3))(fun)) { + _ == ts + } + } + property("zipWith22") = { + // format: off + val ts = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22) + def fun( + t1: Int, t2 : Int, t3: Int, t4: Int, t5: Int, t6: Int, t7: Int, t8: Int, t9: Int, t10: Int, t11: Int, + t12: Int, t13: Int, t14: Int, t15: Int, t16: Int, t17: Int, t18: Int, t19: Int, t20: Int, t21: Int, t22: Int + ) = + (t1, t2,t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22) + + forAll(zipWith( + const(ts._1), const(ts._2), const(ts._3), const(ts._4), const(ts._5), const(ts._6), const(ts._7), const(ts._8), + const(ts._9), const(ts._10), const(ts._11), const(ts._12), const(ts._13), const(ts._14), const(ts._15), + const(ts._16), const(ts._17), const(ts._18), const(ts._19), const(ts._20), const(ts._21), const(ts._22) + )(fun)) { + _ == ts + } + // format: on + } + //// See https://github.com/typelevel/scalacheck/issues/79 property("issue #79") = { val g = oneOf(const(0).suchThat(_ => true), const("0").suchThat(_ => true)) From f48b7aa0f739c979755608f19eb2ab9e1bc54910 Mon Sep 17 00:00:00 2001 From: satorg Date: Sun, 14 Jul 2024 00:45:02 -0700 Subject: [PATCH 3/3] optimize Gen.zipWith code generator --- project/codegen.scala | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/project/codegen.scala b/project/codegen.scala index d73053ac..6a95ec86 100644 --- a/project/codegen.scala +++ b/project/codegen.scala @@ -37,13 +37,6 @@ object codegen { s"$g.flatMap(($t: $T) => $acc)" } - def flatMappedGeneratorsWithFun(i: Int, f: String, s: Seq[(String, String)]): String = - s.init.foldRight(s"${s.last._2}.map { ${s.last._1} => $f(${vals(i)}) }") { - case ((t, g), acc) => - val T = t.toUpperCase - s"$g.flatMap(($t: $T) => $acc)" - } - def vals(i: Int) = csv(idents("t", i)) def coImplicits(i: Int) = (1 to i).map(n => s"co$n: Cogen[T$n]").mkString(",") @@ -114,14 +107,30 @@ object codegen { } def zipWith(i: Int) = { - val gens = flatMappedGeneratorsWithFun(i, "f", idents("t", i) zip idents("g", i)) + val f = "f" + val tR = "R" + val ts = idents("t", i) // Seq(t1, ... ti) + val tTs = idents("T", i) // Seq(T1, ..., Ti) + val gs = idents("g", i) // Seq(g1, ..., gi) + val tTsCsv = csv(tTs) // "T1, ..., Ti" + val tsCsv = csv(ts) // "t1, ..., ti" + val tTts = tTs.zip(ts) // Seq((T1, t1), ..., (Ti, ti)) + val tTtgs = tTts.zip(gs) // Seq(((T1, t1), g1), ..., ((Ti, ti), gi)) + + val ((_, ti), gi) = tTtgs.last + val gens = + tTtgs.init.foldRight(s"$gi.map { $ti => $f($tsCsv) }") { + case (((tT, t), g), acc) => + s"$g.flatMap(($t: $tT) => $acc)" + } + s""" | /** Combines the given generators into a new generator of the given result type | * with help of the given mapping function. */ - | def zipWith[${types(i)},R]( + | def zipWith[$tTsCsv, $tR]( | ${wrappedArgs("Gen", i)} | )( - | f: (${types(i)}) => R + | $f: ($tTsCsv) => $tR | ): Gen[R] = | $gens |""".stripMargin