|
|
|
|
|
by kortex
1562 days ago
|
|
In terms of ergonomics, I'm more a fan of the fluent style [1] over flow-aware typing with guard blocks. I've never heard of till not but I presume you mean that's like where you have like foo: Optional[Foo]
if foo is None:
return some_error_handler()
bar = foo.qux() # the above guard "upgrades" O[Foo] to Foo
For me the real reason I love the ergonomics of the Rust-style "monads [2]" over Unions is that it lets you generically operate on each of 3 orthogonal parts: the value, the error, and the container. Optional or Union[T, E] don't quite hit the same way because you end up having to do more contortions to deal with managing the happy path vs sad path. What ends up often happening is without a container, your type "leaks" into other methods - you start ending up with functions that expect a Union[SomethingMoreSpecific, E], instead of just letting the Result.map(T->U) handle it.Also specifically in Python, the type system is kind of weak (especially those bundled with Pycharm), and a lot of functional operations which ought to be more strongly typed end up with their types erased for whatever reason. In particular functools.partial seems to discard type information more than I'd like. The Result python package [3] doesn't run into this problem near to the same degree. 1] https://martinfowler.com/bliki/FluentInterface.html 2] I find this term frustrating not only because it's infamously ineffable, but also because there appear to be disagreement whether Rust's containers are actual monads or not, leading me to dub what I call the "Engineer's Monad" which is a generic container you can map and flatmap over, even if isn't strictly an Applicative. 3] https://pypi.org/project/result/ |
|