Last active
October 26, 2022 06:46
-
-
Save PaNaVTEC/8b4b198affeb3bbb3ac6afe7d636ffe2 to your computer and use it in GitHub Desktop.
Scala 3 - Arbitrary typeclass derivation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.panavtec.scalacheck | |
import org.scalacheck.Arbitrary | |
import org.scalacheck.Gen | |
import scala.compiletime.{erasedValue, summonInline} | |
import scala.deriving.* | |
object ArbitraryDeriving: | |
inline def summonAll[T <: Tuple]: List[Arbitrary[?]] = | |
inline erasedValue[T] match | |
case _: EmptyTuple => Nil | |
case _: (t *: ts) => summonInline[Arbitrary[t]] :: summonAll[ts] | |
inline given derived[T](using m: Mirror.Of[T]): Arbitrary[T] = | |
val elemInstances = summonAll[m.MirroredElemTypes] | |
inline m match | |
case s: Mirror.SumOf[T] => deriveSum(s, elemInstances) | |
case p: Mirror.ProductOf[T] => deriveProduct(p, elemInstances) | |
def deriveSum[T](s: Mirror.SumOf[T], elems: List[Arbitrary[?]]): Arbitrary[T] = | |
Arbitrary( | |
Gen | |
.chooseNum(0, elems.size - 1) | |
.flatMap(elems(_).arbitrary.asInstanceOf[Gen[T]]) | |
) | |
def deriveProduct[T](p: Mirror.ProductOf[T], elems: List[Arbitrary[?]]): Arbitrary[T] = | |
Arbitrary( | |
elems | |
.foldRight[Gen[Tuple]](Gen.const(EmptyTuple)) { (arb: Arbitrary[?], acc: Gen[Tuple]) => | |
arb.arbitrary.flatMap { gen => acc.map(gen *: _) } | |
} | |
.map(p.fromProduct(_)) | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final case class SomeProduct( | |
id: String, | |
name: String, | |
color: Color | |
) | |
enum Color: | |
case Red | |
case Blue | |
object SomeProduct: | |
val f: SomeProduct = summon[Arbitrary[SomeProduct]].sample.get | |
given Arbitrary[Red.type] = ArbitraryDeriving.derived | |
given Arbitrary[Blue.type] = ArbitraryDeriving.derived | |
given Arbitrary[Color] = ArbitraryDeriving.derived | |
given Arbitrary[SomeProduct] = ArbitraryDeriving.derived | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment