ReadYamlValue
と呼ばれるPlay Json Reads[T]
タイプとよく似たMonadのようなタイプを作成しました。cats + disciplineを使って関数のようなMonadをテストする方法
trait ReadYamlValue[T] {
def read(json: YamlValue): ReadResult[T]
// ... methods include map, flatMap, etc
}
私は、このために猫Monad
インスタンス作成:
implicit val ReadYamlValueMonad: Monad[ReadYamlValue] = new Monad[ReadYamlValue] {
override def flatMap[A, B](fa: ReadYamlValue[A])(f: A => ReadYamlValue[B]): ReadYamlValue[B] = {
fa flatMap f
}
override def tailRecM[A, B](a: A)(f: A => ReadYamlValue[Either[A, B]]): ReadYamlValue[B] = {
ReadYamlValue.read[B] { yaml =>
@tailrec def readB(reader: ReadYamlValue[Either[A, B]]): ReadResult[B] = {
reader.read(yaml) match {
case Good(Left(nextA)) => readB(f(nextA))
case Good(Right(b)) => Good(b)
case Bad(error) => Bad(error)
}
}
readB(f(a))
}
}
override def pure[A](x: A): ReadYamlValue[A] = ReadYamlValue.success(x)
}
をそして私はMonadLaws
とScalaCheckでそれをテストしたいです。
class CatsTests extends FreeSpec with discipline.MonadTests[ReadYamlValue] {
monad[Int, Int, Int].all.check()
}
しかし、私は得る:
could not find implicit value for parameter EqFA: cats.Eq[io.gloriousfuture.yaml.ReadYamlValue[Int]]
私が効果的に機能が何であるかのためEq
を定義するにはどうすればよいですか?関数の平等を比較することは、私が望んでいないように思えます...私のReadYamlValue
クラスは、モナドでも、Functorでもないのですか?
implicit def eqReadYaml[T: Eq: FormatYamlValue: Arbitrary]: Eq[ReadYamlValue[T]] = {
Eq.instance { (a, b) =>
val badYaml = arbitrary[YamlValue].getOrThrow
val goodValue = arbitrary[T].getOrThrow
val goodYaml = Yaml.write(goodValue)
Seq(badYaml, goodYaml).forall { yaml =>
(a.read(yaml), b.read(yaml)) match {
case (Good(av), Good(bv)) => Eq.eqv(av, bv)
case (Bad(ae), Bad(be)) => Eq.eqv(ae, be)
case _ => false
}
}
}
}
しかし、それは平等の定義を少しsidesteppingされるように、これはと思われる:これを行うには
一つの方法は、任意のサンプルを生成し、結果の平等を比較することです。これを行うにはより正統的な方法がありますか?これは、任意のインスタンスを使用してのように見えます
これの唯一の欠点は、両方がうまく「読み取り」されるという単一の例を生成することは考えにくいようである。私はすべて16がエラーの結果となり、成功のケースがテストされないことを恐れる。これは 'MonadLaws'をテストする上で大変重要ですか? –
デコード側では、circeは本当にいくつかの 'A'値を生成し、次にそれらをエンコードして、デコーダが同じことをするようにしてください。 –