Typing issue with chained Result
See original GitHub issueTake the following two functions as an example of two (or more) functions with unique failure modes (each function may fail in their own way)
def fraction(x: float ) -> Result[float, ZeroDivisionError]:
try: return Success(1/x)
except ZeroDivisionError as e: return Failure(e)
def log_of_arg_minus_one(x: float) -> Result[float, ValueError]:
try: return Success(log(1-x))
except ValueError as e: return Failure(e)
then a computation like fraction(x).bind(log_of_arg_minus_one)
has potentially three different outcomes:
- the happy path where both functions return a
Success
, i.e.fraction(x)
returnsSuccess(y)
wherey
is afloat
andlog_of_arg_minus_one(y)
returnsSuccess(z)
wherez
is also a float; examplefraction(2).bind(log_of_arg_minus_one)
- the failure path of
fraction
, i.e.Failure(ZeroDivisionError)
; example:fraction(0).bind(log_of_arg_minus_one)
- the failure path of
log_of_arg_minus_one
, i.e.Failure(ValueError)
; example:fraction(1).bind(log_of_arg_minus_one)
Sadly this seems not to type correctly:
FailureCases = Union[ZeroDivisionError, ValueError]
z: Result[float, FailureCases] = fraction(1).bind(log_of_arg_minus_one)
# Argument 1 to "bind" of "Result" has incompatible type
# "Callable[[float], Result[float, ValueError]]";
# expected "Callable[[float], Result[float, Union[ZeroDivisionError, ValueError]]]"
The following also doesn’t work:
z: Result[float, Exception] = fraction(1).bind(log_of_arg_minus_one)
# Argument 1 to "bind" of "Result" has incompatible type
# "Callable[[float], Result[float, ValueError]]";
# expected "Callable[[float], Result[float, Exception]]"
I don’t know it this is an issue with bind
(that might be fixable with a plugin) or just that Result[S, F]
is not properly covariant with respect to F
i.e. Result[X, A]
is considered a subtype of Result[X, B]
when A
is a subtype of B
Issue Analytics
- State:
- Created 4 years ago
- Comments:25 (10 by maintainers)
Top Results From Across the Web
dependency injection - Typescript typings in chained calls
reduction of the issue to an injection problem. My issue. I'm trying to write some pattern that would allow an object to extend...
Read more >A typed chain: exploring the limits of TypeScript
In my last post, I looked at how some of TypeScript's new features made it possible to correctly type Underscore.js's pluck method. In...
Read more >Action Chaining - Apache Struts
The Chain Result is a result type that invokes an Action with its own Interceptor Stack and Result. This Interceptor allows an Action...
Read more >Optional chaining, proper infer in type guard #34974 - GitHub
I have a similar issue with type guards. This compiles: type Person = { name: string; } ...
Read more >Optional chaining (?.) - JavaScript - MDN Web Docs - Mozilla
This is an idiomatic pattern in JavaScript, but it gets verbose when the chain is long, and it's not safe. For example, if...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@sobolevn I think a better name for the type aggregating
bind
might bechain
(instead ofunify
)Another general issue with the typing of
Result
that I originally mentioned in this issue (but that turned out be unrelated) iscovariance
. Consider:As it currently is (regardless of the original or the proposed behavior) this doesn’t typecheck. I think it should?