4

我正在为我的域模型编写 ScalaCheck 生成器。为了增加灵活性,我的生成器返回函数采用关联的特定值。例如:

case class A(...)
case class B(...)
case class C(a: A, ...)
case class D(b: B, c: C, ...)

val genA: Gen[A] = ???
val genB: Gen[B] = ???
val genC: (A) => Gen[C] = ???
val genD: (B, C) => Gen[D] = ???

这样,我可以选择生成C与特定A. 不过,我通常不在乎模型与什么相关联:我想生成C带有 any的A. 在这种情况下,我可以执行以下操作之一:

for {
  a <- genA
  c <- genC(a)
} yield c

// Or, desugared and simplified:
genA flatMap genC

// Or, with a Scalaz Monad for Gen
genA >>= genC
Kleisli(genC) =<< genA

我喜欢后面的选项,因为我可以将它们包含在更复杂的表达式中,而无需相对繁琐的for循环。D但是,对于这种需要多个参数的情况,我想不出任何简单的解决方案。看来我被困在了for

for {
  a <- genA
  b <- genB
  c <- genC(a)
  d <- genD(b, c)
} yield d

底线

如果有一些干净的语法不仅可以将 Kleisli 箭头和带有n 个参数f: T => M[R]的“类 Kleisli”函数提升到单子值或. 像这样的东西:g: (T, U) => M[R]f2: M[T] => M[R]g2: (M[T], M[U]) => M[R]

// liftX is a hypothetical lifting method enriched onto Function1-N:
genD.liftX(genB, genC.liftX(genA))

我喜欢这种假设方法的原因在于:

  • 看起来类似一个未提升的功能应用程序,只是有liftX拼接
  • 很容易组合成复杂的genC表达式genD

我可以写它,但在广阔的Scalaz世界中是否存在这样的东西?如果我对我的多参数函数进行柯里化会有帮助吗?Arrow 组合器会有帮助吗?我一直在浏览 Scalaz 并没有提出任何类似的东西,但我想我会问一下,以防以前有人遇到过这个问题。

4

0 回答 0