Skip to content

Commit

Permalink
Make Option covariant (#190)
Browse files Browse the repository at this point in the history
* Make Option covariant

* Use a separate covariant out type

* Fixed Result covariance
  • Loading branch information
dbrattli authored Sep 17, 2024
1 parent 65cd3a9 commit 06e6f15
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 238 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
> Pragmatic functional programming
Expression aims to be a solid, type-safe, pragmatic, and high performance
library for frictionless and practical functional programming in Python 3.11+.
library for frictionless and practical functional programming in Python 3.10+.

By pragmatic, we mean that the goal of the library is to use simple abstractions
to enable you to do practical and productive functional programming in Python
Expand Down Expand Up @@ -57,7 +57,7 @@ similar to Python, but F# can also do a lot of things better than Python:
## Getting Started

You can install the latest `expression` from PyPI by running `pip` (or
`pip3`). Note that `expression` only works for Python 3.11+.
`pip3`). Note that `expression` only works for Python 3.10+.

```console
> pip install expression
Expand Down Expand Up @@ -88,7 +88,7 @@ To add Pydantic v2 support, install the `pydantic` extra:
functions and methods.
- Support PEP 634 and structural pattern matching.
- Code must pass strict static type checking by
[pylance](https://devblogs.microsoft.com/python/announcing-pylance-fast-feature-rich-language-support-for-python-in-visual-studio-code/).
[Pylance](https://devblogs.microsoft.com/python/announcing-pylance-fast-feature-rich-language-support-for-python-in-visual-studio-code/).
Pylance is awesome, use it!
- [Pydantic](https://pydantic-docs.helpmanual.io/) friendly data types. Use Expression
types as part of your Pydantic data model and (de)serialize to/from JSON.
Expand Down Expand Up @@ -325,7 +325,6 @@ The map2 function allows us to achieve this behavior. It takes two Option values

This approach ensures that our combined value reflects the presence or absence of data in the original Options.


```python
from expression import Some, Nothing, Option
from operator import add
Expand Down
105 changes: 56 additions & 49 deletions expression/core/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
_J = TypeVar("_J")

_P = TypeVarTuple("_P")
_Q = TypeVarTuple("_Q")
_X = TypeVarTuple("_X")
_Y = TypeVarTuple("_Y")
_Z = TypeVarTuple("_Z")
Expand All @@ -41,70 +40,76 @@ def compose(__fn1: Callable[[_A], _B], __fn2: Callable[[_B], _C], __fn3: Callabl

@overload
def compose(
__fn1: Callable[[_A], _B],
__fn2: Callable[[_B], _C],
__fn3: Callable[[_C], _D],
__fn4: Callable[[_D], _E],
fn1: Callable[[_A], _B],
fn2: Callable[[_B], _C],
fn3: Callable[[_C], _D],
fn4: Callable[[_D], _E],
/,
) -> Callable[[_A], _E]: ...


@overload
def compose(
__fn1: Callable[[_A], _B],
__fn2: Callable[[_B], _C],
__fn3: Callable[[_C], _D],
__fn4: Callable[[_D], _E],
__fn5: Callable[[_E], _F],
fn1: Callable[[_A], _B],
fn2: Callable[[_B], _C],
fn3: Callable[[_C], _D],
fn4: Callable[[_D], _E],
fn5: Callable[[_E], _F],
/,
) -> Callable[[_A], _F]: ...


@overload
def compose(
__fn1: Callable[[_A], _B],
__fn2: Callable[[_B], _C],
__fn3: Callable[[_C], _D],
__fn4: Callable[[_D], _E],
__fn5: Callable[[_E], _F],
__fn6: Callable[[_F], _G],
fn1: Callable[[_A], _B],
fn2: Callable[[_B], _C],
fn3: Callable[[_C], _D],
fn4: Callable[[_D], _E],
fn5: Callable[[_E], _F],
fn6: Callable[[_F], _G],
/,
) -> Callable[[_A], _G]: ...


@overload
def compose(
__fn1: Callable[[_A], _B],
__fn2: Callable[[_B], _C],
__fn3: Callable[[_C], _D],
__fn4: Callable[[_D], _E],
__fn5: Callable[[_E], _F],
__fn6: Callable[[_F], _G],
__fn7: Callable[[_G], _H],
fn1: Callable[[_A], _B],
fn2: Callable[[_B], _C],
fn3: Callable[[_C], _D],
fn4: Callable[[_D], _E],
fn5: Callable[[_E], _F],
fn6: Callable[[_F], _G],
fn7: Callable[[_G], _H],
/,
) -> Callable[[_A], _H]: ...


@overload
def compose(
__fn1: Callable[[_A], _B],
__fn2: Callable[[_B], _C],
__fn3: Callable[[_C], _D],
__fn4: Callable[[_D], _E],
__fn5: Callable[[_E], _F],
__fn6: Callable[[_F], _G],
__fn7: Callable[[_G], _H],
__fn8: Callable[[_H], _T],
fn1: Callable[[_A], _B],
fn2: Callable[[_B], _C],
fn3: Callable[[_C], _D],
fn4: Callable[[_D], _E],
fn5: Callable[[_E], _F],
fn6: Callable[[_F], _G],
fn7: Callable[[_G], _H],
fn8: Callable[[_H], _T],
/,
) -> Callable[[_A], _T]: ...


@overload
def compose(
__fn1: Callable[[_A], _B],
__fn2: Callable[[_B], _C],
__fn3: Callable[[_C], _D],
__fn4: Callable[[_D], _E],
__fn5: Callable[[_E], _F],
__fn6: Callable[[_F], _G],
__fn7: Callable[[_G], _H],
__fn8: Callable[[_H], _T],
__fn9: Callable[[_T], _J],
fn1: Callable[[_A], _B],
fn2: Callable[[_B], _C],
fn3: Callable[[_C], _D],
fn4: Callable[[_D], _E],
fn5: Callable[[_E], _F],
fn6: Callable[[_F], _G],
fn7: Callable[[_G], _H],
fn8: Callable[[_H], _T],
fn9: Callable[[_T], _J],
/,
) -> Callable[[_A], _J]: ...


Expand Down Expand Up @@ -141,29 +146,31 @@ def starcompose() -> Callable[[Any], Any]: ...


@overload
def starcompose(__fn1: Callable[[Unpack[_P]], _A]) -> Callable[[Unpack[_P]], _A]: ...
def starcompose(fn1: Callable[[Unpack[_P]], _A], /) -> Callable[[Unpack[_P]], _A]: ...


@overload
def starcompose(
__fn1: Callable[[Unpack[_P]], tuple[Unpack[_Y]]], __fn2: Callable[[Unpack[_Y]], _B]
fn1: Callable[[Unpack[_P]], tuple[Unpack[_Y]]], fn2: Callable[[Unpack[_Y]], _B], /
) -> Callable[[Unpack[_P]], _B]: ...


@overload
def starcompose(
__fn1: Callable[[Unpack[_P]], tuple[Unpack[_Y]]],
__fn2: Callable[[Unpack[_Y]], tuple[Unpack[_Z]]],
__fn3: Callable[[Unpack[_Z]], _C],
fn1: Callable[[Unpack[_P]], tuple[Unpack[_Y]]],
fn2: Callable[[Unpack[_Y]], tuple[Unpack[_Z]]],
fn3: Callable[[Unpack[_Z]], _C],
/,
) -> Callable[[Unpack[_P]], _C]: ...


@overload
def starcompose(
__fn1: Callable[[Unpack[_P]], tuple[Unpack[_Y]]],
__fn2: Callable[[Unpack[_Y]], tuple[Unpack[_Z]]],
__fn3: Callable[[Unpack[_Z]], tuple[Unpack[_X]]],
__fn4: Callable[[Unpack[_X]], _D],
fn1: Callable[[Unpack[_P]], tuple[Unpack[_Y]]],
fn2: Callable[[Unpack[_Y]], tuple[Unpack[_Z]]],
fn3: Callable[[Unpack[_Z]], tuple[Unpack[_X]]],
fn4: Callable[[Unpack[_X]], _D],
/,
) -> Callable[[Unpack[_P]], _D]: ...


Expand Down
Loading

0 comments on commit 06e6f15

Please sign in to comment.