I'm writing ScalaCheck generators for my domain models. For added flexibility, my generator-returning functions take specific values for the associations. For example:
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] = ???
This way, I have the option of generating arbitrary C
's that are associated with a specific A
. Often, though, I don't care what the model is associated with: I want to generate a C
with any A
. In that case, I can do one of these:
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
I like having the latter options because I can include them in more complicated expressions without the relatively cumbersome for
loop. However, I can't come up with any simple solutions for cases like D
that take more than one argument. It seems I'm stuck with the for
:
for {
a <- genA
b <- genB
c <- genC(a)
d <- genD(b, c)
} yield d
Bottom Line:
I would really appreciate it if there was some clean syntax for lifting not only a Kleisli arrow like f: T => M[R]
, but also a "Kleisli-like" function with n arguments g: (T, U) => M[R]
, onto a function over monadic values f2: M[T] => M[R]
or g2: (M[T], M[U]) => M[R]
. Something like this:
// liftX is a hypothetical lifting method enriched onto Function1-N:
genD.liftX(genB, genC.liftX(genA))
What I like about this hypothetical method is that it:
- looks similar an unlifted function application, just with the
liftX
spliced in - is easy to compose into a complicated expression (see the lifting of
genC
inside the lifting ofgenD
)
I could write it, but does something like this exist in the vast world of Scalaz? Would it help if I curried my multi-argument functions? Would Arrow combinators help? I've been browsing Scalaz for a while and haven't come up with anything similar, but I thought I'd ask in case anyone has run into this before.