【问题标题】:Is it possible to write a Distributive Instance for ScalaCheck's Gen type?是否可以为 ScalaCheck 的 Gen 类型编写分布式实例?
【发布时间】:2020-04-03 01:09:39
【问题描述】:

我正在尝试为 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, *]] {
        ...
    }
}

在写这篇文章时,我意识到如果我能够为Gen 写一个Distributive 实例将会很有用,因为这样我就可以在下面为GeneratorTflatMap(有点复杂)方式:

    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)))
    }

本能地,我觉得我应该能够为Gen 编写一个Distributive 实例,因为Gen 或多或少只是一些配置的函数和种子,一个值,函数是分布的。

话虽如此,我没有找到任何人这样做的例子,我正在努力编写它,因为 ScalaCheck 没有暴露Gen 的内部结构。

这可能吗?

【问题讨论】:

    标签: scala functional-programming monad-transformers scala-cats scalacheck


    【解决方案1】:

    我想我明白为什么这不太可能;这是因为Gen 支持过滤,因此,有可能以没有有效值的Gen 结束。

    我认为Gen 是一个函数(Properties, Seed) => A,但实际上,这应该更像(Properties, Seed) => Option[A]

    第一种分发,第二种不分发。

    例如,如果Gen 可能失败,则无法将IO[Gen[A]] 转换为Gen[IO[A]],因为如果不评估IO,就无法知道失败。

    如果您假设任何生成器在评估足够多的情况下都会产生一个值,并且您愿意在不是这种情况下遇到异常,那么可以像这样实现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)
      }
    

    【讨论】:

    • 我将推迟接受这个答案,因为我仍然不能 100% 确定它,并希望给它一个更正的机会
    猜你喜欢
    • 1970-01-01
    • 2022-08-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多