Open sidnt opened 4 years ago
R1 is a subtype of R
since R1 is meant to be fed to the resultant ZIO, it should cater to the needs of R as well. Ie, it should be treatable as R. Which is established when we constrain R1 <: R. And then after this, R1 can contain its own characteristics that would to cater to the requirements of the that
effect.
The resultant effect can fail with E1, ie, it can be an error from either the this
effect or the that
effect. But for both, we are getting the same E1 type. ie, E1 needs to represent both the errors from this
and that
effects. So
its documentation reads interesting:
but what do we understand by a sequential zip? it means, a) the effect returned from running effectA.zipWith(effectB), will itself be an effectC, ie, just another description.
that description, will read very much like:
this
effectA to compute a:Athat
effectB to compute b:B(smell a for comprehension?)
so far so good for types ABC. but what about RE R1E1?
this tells a lot of story, as we shall see. let's pay attention to types.
the current zio instance, already has it's -R+E+A types. if we look at the signature of zipWith, it uses the REA types, so any such zipWith invocation would be aware of its REA types. based on that, we encode some constraints on the arguments to this method, particularly, on their types, ie, on the types of
that
andf
. we express these constraints in the type bounds in the [ ] next to zipWith, ie,we don't want any subcomponent of our program, either depending on something the parent couldn't/didn't provide, or return something which the parent program doesn't know how to handle. these are constraints on what it can return back to handle, or what it can require from us to work.
our first requirement is, now zipWith is given the freedom to return a new effect. but since we are using zio model of types telling us everything about an instance, we expect the REA are the finally inferred types, that tell the entire scope, width and breadth of the zio instance. that to run it, we need to provide R, on running, it might fail with an e:E, or succeed with an a:A.
if we imagine the root fuse of a typical webserver, R will be a rich type, telling us a lot about the configuration and tuning parameters for the given effect, but E and A might as well be
Nothing
. meaning we have programmed our effect so well, that it will not fail, and keep running forever, so neither it will return any value.but this is not always the case for smaller components outer in the wild. we see deviations from Nothing. especially, with smaller effects wired all over the place in the root effect, because these smaller effects need to be explicit and declarative about the types; what exactly do they need to function properly, and what exactly will they give us back to handle; when communicating with other effects, by exchanging information, in kicking off subsequent effects, or dealing with return values from others, they called into earlier.
we don't normally observe this, but the new R1E1BC types, are also parameters to this function, taken from the types of
that
andf
.whatever R1E1BC type is, it must fulfil the [ ] encoded constraint, which is
there are no bounds on B and C, they can be any arbitrary type. basically the
f: (A, B) => C