是否可以为ScalaCheck的Gen类型编写一个分配实例?

问题描述 投票:0回答:1

我正在尝试为ScalaCheck的Gen类型编写一个Monad Transformer实例。

即:如下类型,可以用作Monad,前提是底层函子F是Monad。

case class GeneratorT[F[_], A](generator: Gen[F[A]])

object GeneratorT {
  implicit def monadForGeneratorT[F[_]: Monad]: Monad[GeneratorT[F, *]] = new Monad[GeneratorT[F, *]] {
        ...
    }
}

[在编写此代码时,我意识到如果能够为Distributive编写Gen实例,那将很有用,因为这样我就可以在下面为flatMap编写GeneratorT了(有点复杂的方式:

    override def flatMap[A, B](ga: GeneratorT[F, A])(fun: A => GeneratorT[F, B]): GeneratorT[F, B] = {
      GeneratorT[F, B](ga.generator.flatMap(fa => fa.map(a => fun(a).generator).distribute(identity).map(_.flatten)))
    }

[本能地,我觉得我应该能够为Distributive编写Gen实例,因为Gen或多或少只是来自某些配置的函数,以及将种子添加到值上,以及功能是分布式的。

话虽如此,但我没有找到任何这样做的例子,并且我正在努力编写它,因为ScalaCheck不会公开Gen的内部。

这可能吗?

scala functional-programming monad-transformers scala-cats scalacheck
1个回答
0
投票

我想我理解为什么这不太可能;这是因为Gen支持过滤,因此,可能会以没有有效值的Gen结尾。我本来以为Gen是函数(Properties, Seed) => A,但实际上,它应该更像(Properties, Seed) => Option[A]。第一种分布,第二种不分布。例如,如果IO[Gen[A]]可能失败,则无法将Gen[IO[A]]转换为Gen,因为如果不评估IO,就无法了解故障。

[如果您假装任何Generator如果评估足够的次数都将产生一个值,并且您愿意在这种情况下遇到异常,则可以像这样隐含Distributive

  implicit val distributiveForGen: Distributive[Gen] = new Distributive[Gen] {
    override def distribute[G[_]: Functor, A, B](ga: G[A])(f: A => Gen[B]): Gen[G[B]] =
      Gen.parameterized(params => ga.map(a => f(a).pureApply(params, params.initialSeed.getOrElse(Seed(0)))))

    override def map[A, B](fa: Gen[A])(f: A => B): Gen[B] = fa.map(f)
  }
© www.soinside.com 2019 - 2024. All rights reserved.