I am trying to create a compositional batching mechanism.
The process flow must be.
- Accumulate the state in the form of
s: Map[BatchFragmentId, FragmentRequest] - Compute the result in the form of
Map[BatchFragmentId, FragmentResponse] - Perform a series of pre-defined computations which are of the form
f: Map[BatchFragmentId, FragmentResponse] => Rfor some result R.
My solution
Let Batch[R] be a monad, which contains some acccumualted state s and some function f.
map[B](g: R => B) makes perfect sense since it is simply a compositon of the self-contained function f (Batch.make(f=f.andThen(g), s=s).
flatMap[B](f: R => Batch[B]) on the hand does not make much sense, since R requires the computation to be completed, thus Batch[B] cannot exist at this point, since s must contain Batch[B]'s state when performing the response computation.
Modifying flatMap:
def combine[B, C](that: Batch[B])(t: (A, B) => C): Batch[C] = {
val combined: Map[BatchFragmentId, FragmentRequest] = that.state ++ state
val g: Map[BatchFragmentId, FragmentResponse] => C =
(r: Map[BatchFragmentId, FragmentResponse]) => t(f(r), that.f(r))
Batch.make(combined, g)
}
This does not play well with Scala's for comprehensions and it's readability deteriorates more rapidly, than a for comprehension.
val b: Batch[String] = ???
val b2: Batch[String] = ???
val b3: Batch[Int] = ???
val combined: Batch[(String, String)] =
(b.combine(b2){ case (s1, s2) => s1 + s2 })
.combine(b3){ case (s1, i1) => s1 + i1.toString }
Which can become very messy given a couple of batches. The desired way to be able compose these batches would be.
val o: Batch[(String, String)] = for {
_ <- put("key", "42")
x1 <- get("key")
_ <- put("key2", "24")
x2 <- get("key2")
} yield (x1, x2)
But any elegant syntax would be a solution.
I am not that well versed in category theory and have limited experience with writing code in this form, so I am unsure of what type classes to look into for this particular problem.
Is this even the right approach for such a problem; am I modelling the problem appropriately? Is this problem already well understood and generalized?
I have cats at my disposal also.