It might be interesting to get a bit concrete with the 23-effect function. So here is a list of the effects (annotated and lightly redacted)!
( Concurrent :> es -- standard from 'effectful'
, IOE :> es -- standard from effectful
, Statement :> es -- DB statements
, DB :> es -- DB transactions
, Trace :> es -- opentelemetry tracing
, AWS :> es -- AWS
, Log :> es -- `log-base` compatibility via 'log-effectful'
, StructuredConcurrency :> es -- ki compatibility via 'ki-effectful'
, Labeled "backgroundTasks" (Reader Ki.Scope) :> es -- ki scope for background tasks
, Resource :> es -- resourcet via 'resourcet-effectful'
, Time :> es -- time access via 'monad-time-effectful'
, Retry :> es -- retrying via 'retry-effectful'
, Writer T :> es -- locally used to track work we didn't finish
-- plus
-- 4 internal effects relating to specific computer vision tasks
-- 3 internal effects relating to global subsystems
-- 2 minor utility custom effects
)
What I think is interesting here is that I don’t think it’s the case that this is extraordinarily fine-grained. Maybe some of the DB effects could be lumped together; and it’s kind of annoying that we have both Concurrent
and StructuredConcurrency
. But pretty much everything else corresponds to different, quite substantial things that this function needs.
Now of course some of this can be split up: we do generally have separate functions that fetch what we need from the database, and then other functions that consume it. But this is (nearly) a top-level one, so has pretty much everything.
So possibly it’s just that we have to do an unusually large amount of stuff. But I also think it’s not too hard to hit 10+ effects while doing only a reasonably large amount of stuff: a few standard effects, plus some database effects, plus a couple of custom ones and you’re there!