Skip to content

Instantly share code, notes, and snippets.

@manojo
Created July 6, 2017 09:11
Show Gist options
  • Save manojo/84e60e6f8101e0e459ae3242520e3bcb to your computer and use it in GitHub Desktop.
Save manojo/84e60e6f8101e0e459ae3242520e3bcb to your computer and use it in GitHub Desktop.
Generators using type classes and derivations
import shapeless._
object enumerate {
trait Gen[T] {
def gen: Stream[T]
}
object Gen {
def mkGen[T](st: Stream[T]): Gen[T] = new Gen[T] {
def gen = st
}
implicit val genInt: Gen[Int] = mkGen[Int] (0 #:: 1 #:: Stream.empty)
implicit def genGeneric[T, R]
(implicit
generic: Generic.Aux[T, R],
genRepr: Lazy[Gen[R]]
): Gen[T] = mkGen(genRepr.value.gen.map(r => generic.from(r)))
//base case for products
implicit val genHNil: Gen[HNil] = mkGen(HNil #:: Stream.empty)
//induction for products
implicit def genHCons[H, T <: HList]
(implicit
genH: Lazy[Gen[H]],
genT: Lazy[Gen[T]]
): Gen[H :: T] = mkGen(
for (h <- genH.value.gen; tl <- genT.value.gen) yield (h :: tl)
)
//base case for coproducts
implicit val genCNil: Gen[CNil] = mkGen(Stream.empty)
implicit def genCCons[H, T <: Coproduct]
(implicit
genH: Lazy[Gen[H]],
genT: Lazy[Gen[T]]
): Gen[H :+: T] = mkGen {
val hd = genH.value.gen.map(Inl.apply)
val tl = genT.value.gen.map(Inr.apply)
hd ++ tl
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment