我正在为我的域模型编写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
与任何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
底线:
如果有一些干净的语法可以解除不仅像f: T => M[R]
这样的Kleisli箭头,而且还有一个像 n <的“类似Kleisli”的函数,我将非常感激。 / em>参数g: (T, U) => M[R]
,关于monadic值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一段时间并没有提出类似的东西,但我想我会问,以防有人遇到过这种情况。