This sounds like a generalization of "rethrowing" annotations of exceptions from certain languages (I have the most experience with Swift), and it seems more principled than those; on the surface it's even kind of neat.
However, I've found that in practice, polymorphism over effects quickly becomes painful and redundant in the setting of higher-order functions. To elaborate on that:
- Suppose there is a higher-order function
h
taking a functional argumentf
- The functional argument
f
may or may not be effectful - Most often, one wants the effectfulness of
h
to match that off
- If the default is "pure" (or, in the special case of exceptions, "non-throwing"), then it is almost always necessary to write out the effect polymorphism (or the "rethrows" annotations), otherwise
h
will not be usable with an effectfulf
.- (On the other hand, if the default was impure, that would:
- be weird and contrary to principles of functional languages as well as Rust, and
- either make a pure
f
unusable by a non-polymorphich
or result in a high number of purity violation false positives.)
- (On the other hand, if the default was impure, that would:
- So, now it becomes an API design good practice to always or at least by default make higher-order functions effect-generic.
- At this point, the annotation becomes redundant, while APIs that don't consider this problem become unusable with some functional arguments that they should be able to accept otherwise.
I've written about this problem in more detail previously: one, two.