Skip to content

Commit ad7be9f

Browse files
committed
Renames methods
1 parent 69b1311 commit ad7be9f

22 files changed

+143
-145
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
We follow Semantic Versions since the `0.1.0` release.
44

55

6-
## Version 0.4.0
6+
## Version 0.4.0 aka Goodbye, Monads!
77

88
### Features
99

1010
- Moves all types to `.pyi` files
1111
- Renames all classes according to new naming pattern
1212
- **HUGE** improvement of types
13+
- Renames `fmap` to `map`
14+
- Renames `do_notation` to `pipeline`, moves it to `functions.py`
15+
- Renames `ebind` to `rescue`
16+
- Renames `efmap` to `fix`
1317

1418

1519
## Version 0.3.1

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ TODO: example with `requests` and `json`
3030

3131

3232
```python
33-
from returns.do_notation import do_notation
33+
from returns.pipeline import pipeline
3434
from returns.result import Result, Success, Failure
3535

3636
class CreateAccountAndUser(object):
3737
"""Creates new Account-User pair."""
3838

39-
@do_notation
39+
@pipeline
4040
def __call__(self, username: str, email: str) -> Result['User', str]:
4141
"""Can return a Success(user) or Failure(str_reason)."""
4242
user_schema = self._validate_user(username, email).unwrap()

docs/pages/do-notation.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Here's the code to illustrate the task.
2525

2626
.. code:: python
2727
28-
from returns.do_notation import do_notation
28+
from returns.pipeline import pipeline
2929
from returns.result import Result, Success, Failure
3030
3131
@@ -87,7 +87,7 @@ And here's how we can refactor this monadic code to be more clear.
8787
class CreateAccountAndUser(object):
8888
"""Creates new Account-User pair."""
8989
90-
@do_notation
90+
@pipeline
9191
def __call__(self, username: str, email: str) -> Result['User', str]:
9292
"""Can return a Success(user) or Failure(str_reason)."""
9393
user_schema = self._validate_user(username, email).unwrap()
@@ -102,7 +102,7 @@ Let's see how this new ``.unwrap()`` method works:
102102
- if you monad is ``Success`` it will return its inner value
103103
- if your monad is ``Failure`` it will raise a ``UnwrapFailedError``
104104

105-
And that's where ``@do_notation`` decorator becomes in handy.
105+
And that's where ``@pipeline`` decorator becomes in handy.
106106
It will catch any ``UnwrapFailedError`` during the pipeline
107107
and then return a simple ``Failure`` monad.
108108

@@ -131,7 +131,7 @@ And that's it!
131131

132132
See also:
133133
- https://dry-rb.org/gems/returns/do-notation/
134-
- https://en.wikibooks.org/wiki/Haskell/do_notation
134+
- https://en.wikibooks.org/wiki/Haskell/pipeline
135135
- https://wiki.haskell.org/Do_notation_considered_harmful
136136

137137
Limitations
@@ -143,10 +143,10 @@ due to `mypy issue <https://github.com/python/mypy/issues/3157>`_:
143143

144144
.. code:: python
145145
146-
from returns.do_notation import do_notation
146+
from returns.pipeline import pipeline
147147
from returns.result import Success
148148
149-
@do_notation
149+
@pipeline
150150
def function(param: int) -> Success[int]:
151151
return Success(param)
152152
@@ -164,5 +164,5 @@ with these implementations:
164164
API Reference
165165
-------------
166166

167-
.. automodule:: returns.do_notation
167+
.. automodule:: returns.pipeline
168168
:members:

docs/pages/monad.rst

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ Creating new monads
3535
~~~~~~~~~~~~~~~~~~~
3636

3737
We use two methods to create new monads from the previous one.
38-
``bind`` and ``fmap``.
38+
``bind`` and ``map``.
3939

4040
The difference is simple:
4141

42-
- ``fmap`` works with functions that return regular values
42+
- ``map`` works with functions that return regular values
4343
- ``bind`` works with functions that return monads
4444

4545
:func:`Monad.bind <returns.primitives.monad.Monad.bind>`
@@ -58,7 +58,7 @@ is used to literally bind two different monads together.
5858
So, the rule is: whenever you have some impure functions,
5959
it should return a monad instead.
6060

61-
And we use :func:`Monad.fmap <returns.primitives.monad.Monad.fmap>`
61+
And we use :func:`Monad.map <returns.primitives.monad.Monad.map>`
6262
to use monads with pure functions.
6363

6464
.. code:: python
@@ -68,7 +68,7 @@ to use monads with pure functions.
6868
def double(state: int) -> int:
6969
return state * 2
7070
71-
result = Success(1).fmap(double)
71+
result = Success(1).map(double)
7272
# => Will be equal to Success(2)
7373
7474
Reverse operations
@@ -77,12 +77,12 @@ Reverse operations
7777
We also support two special methods to work with "failed"
7878
monads like ``Failure`` and ``Nothing``:
7979

80-
- :func:`Monad.efmap <returns.primitives.monad.Monad.efmap>` the opposite
81-
of ``fmap`` method that works only when monad is failed
82-
- :func:`Monad.ebind <returns.primitives.monad.Monad.ebind>` the opposite
80+
- :func:`Monad.fix <returns.primitives.monad.Monad.fix>` the opposite
81+
of ``map`` method that works only when monad is failed
82+
- :func:`Monad.rescue <returns.primitives.monad.Monad.rescue>` the opposite
8383
of ``bind`` method that works only when monad is failed
8484

85-
``efmap`` can be used to fix some fixable errors
85+
``fix`` can be used to fix some fixable errors
8686
during the pipeline execution:
8787

8888
.. code:: python
@@ -92,10 +92,10 @@ during the pipeline execution:
9292
def double(state: int) -> float:
9393
return state * 2.0
9494
95-
Failure(1).efmap(double)
95+
Failure(1).fix(double)
9696
# => Will be equal to Success(2.0)
9797
98-
``ebind`` can return any monad you want.
98+
``rescue`` can return any monad you want.
9999
It can also fix your flow and get on the Success track again:
100100

101101
.. code:: python
@@ -107,7 +107,7 @@ It can also fix your flow and get on the Success track again:
107107
return Success(0)
108108
return Failure(state)
109109
110-
Failure(ZeroDivisionError).ebind(fix)
110+
Failure(ZeroDivisionError).rescue(fix)
111111
# => Will be equal to Success(0)
112112
113113
Unwrapping values
@@ -172,13 +172,13 @@ Using lambda functions
172172
Please, do not use ``lambda`` functions in ``python``. Why?
173173
Because all ``lambda`` functions arguments are typed as ``Any``.
174174
This way you won't have any practical typing features
175-
from ``fmap`` and ``bind`` methods.
175+
from ``map`` and ``bind`` methods.
176176

177177
So, instead of:
178178

179179
.. code:: python
180180
181-
some_monad.fmap(lambda x: x + 2) #: Callable[[Any], Any]
181+
some_monad.map(lambda x: x + 2) #: Callable[[Any], Any]
182182
183183
Write:
184184

@@ -189,7 +189,7 @@ Write:
189189
def increment(addition: int, number: int) -> int:
190190
return number + addition
191191
192-
some_monad.fmap(partial(increment, 2)) #: functools.partial[builtins.int*]
192+
some_monad.map(partial(increment, 2)) #: functools.partial[builtins.int*]
193193
194194
This way your code will be type-safe from errors.
195195

returns/do_notation.py

Lines changed: 0 additions & 20 deletions
This file was deleted.

returns/do_notation.pyi

Lines changed: 0 additions & 13 deletions
This file was deleted.

returns/functions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,18 @@ def decorator(*args, **kwargs):
3030
except Exception as exc:
3131
return Failure(exc)
3232
return decorator
33+
34+
35+
def pipeline(function):
36+
"""
37+
Decorator to enable 'do-notation' context.
38+
39+
Should be used for series of computations that rely on ``.unwrap`` method.
40+
"""
41+
@wraps(function)
42+
def decorator(*args, **kwargs):
43+
try:
44+
return function(*args, **kwargs)
45+
except UnwrapFailedError as exc:
46+
return exc.halted_monad
47+
return decorator

returns/functions.pyi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ from returns.primitives.monad import Monad
66
from returns.result import Result
77

88
_MonadType = TypeVar('_MonadType', bound=Monad)
9+
_ReturnsMonadType = TypeVar('_ReturnsMonadType', bound=Callable[..., Monad])
910
_ReturnType = TypeVar('_ReturnType')
1011

1112

@@ -16,6 +17,10 @@ def is_successful(monad: _MonadType) -> bool:
1617
# Typing decorators is not an easy task, see:
1718
# https://github.com/python/mypy/issues/3157
1819

20+
def pipeline(function: _ReturnsMonadType) -> _ReturnsMonadType:
21+
...
22+
23+
1924
def safe(
2025
function: Callable[..., _ReturnType],
2126
) -> Callable[..., Result[_ReturnType, Exception]]:

returns/maybe.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ def __init__(self, inner_value=None):
3939
"""
4040
object.__setattr__(self, '_inner_value', inner_value)
4141

42-
def fmap(self, function):
42+
def map(self, function): # noqa: A003
4343
"""Returns the 'Nothing' instance that was used to call the method."""
4444
return self
4545

4646
def bind(self, function):
4747
"""Returns the 'Nothing' instance that was used to call the method."""
4848
return self
4949

50-
def efmap(self, function):
50+
def fix(self, function):
5151
"""
5252
Applies function to the inner value.
5353
@@ -58,7 +58,7 @@ def efmap(self, function):
5858
"""
5959
return Some(function(self._inner_value))
6060

61-
def ebind(self, function):
61+
def rescue(self, function):
6262
"""
6363
Applies 'function' to the result of a previous calculation.
6464
@@ -87,7 +87,7 @@ class Some(Maybe[_ValueType]):
8787
Quite similar to ``Success`` type.
8888
"""
8989

90-
def fmap(self, function):
90+
def map(self, function): # noqa: A003
9191
"""
9292
Applies function to the inner value.
9393
@@ -107,11 +107,11 @@ def bind(self, function):
107107
"""
108108
return function(self._inner_value)
109109

110-
def efmap(self, function):
110+
def fix(self, function):
111111
"""Returns the 'Some' instance that was used to call the method."""
112112
return self
113113

114-
def ebind(self, function):
114+
def rescue(self, function):
115115
"""Returns the 'Some' instance that was used to call the method."""
116116
return self
117117

returns/maybe.pyi

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class Maybe(GenericMonadOneSlot[_ValueType], metaclass=ABCMeta):
2323
def new(cls, inner_value: _ValueType) -> 'Some[_ValueType]':
2424
...
2525

26-
def fmap(
26+
def map( # noqa: A003
2727
self,
2828
function: Callable[[_ValueType], _NewValueType],
2929
) -> Union['Some[_NewValueType]', 'Maybe[_ValueType]']:
@@ -35,13 +35,13 @@ class Maybe(GenericMonadOneSlot[_ValueType], metaclass=ABCMeta):
3535
) -> Union[_MonadType, 'Maybe[_ValueType]']:
3636
...
3737

38-
def efmap(
38+
def fix(
3939
self,
4040
function: Callable[[Literal[None]], '_NewValueType'],
4141
) -> Union['Some[_ValueType]', 'Some[_NewValueType]']:
4242
...
4343

44-
def ebind(
44+
def rescue(
4545
self,
4646
function: Callable[[Literal[None]], _MonadType],
4747
) -> Union[_MonadType, 'Maybe[_ValueType]']:
@@ -67,19 +67,19 @@ class Nothing(Maybe[Any]):
6767
def __init__(self, inner_value: Literal[None] = ...) -> None:
6868
...
6969

70-
def fmap(self, function) -> 'Nothing':
70+
def map(self, function) -> 'Nothing': # noqa: A003
7171
...
7272

7373
def bind(self, function) -> 'Nothing':
7474
...
7575

76-
def efmap(
76+
def fix(
7777
self,
7878
function: Callable[[Literal[None]], '_NewValueType'],
7979
) -> 'Some[_NewValueType]':
8080
...
8181

82-
def ebind(
82+
def rescue(
8383
self,
8484
function: Callable[[Literal[None]], _MonadType],
8585
) -> _MonadType:
@@ -102,7 +102,7 @@ class Some(Maybe[_ValueType]):
102102
def __init__(self, inner_value: _ValueType) -> None:
103103
...
104104

105-
def fmap(
105+
def map( # noqa: A003
106106
self,
107107
function: Callable[[_ValueType], _NewValueType],
108108
) -> 'Some[_NewValueType]':
@@ -114,10 +114,10 @@ class Some(Maybe[_ValueType]):
114114
) -> _MonadType:
115115
...
116116

117-
def efmap(self, function) -> 'Some[_ValueType]':
117+
def fix(self, function) -> 'Some[_ValueType]':
118118
...
119119

120-
def ebind(self, function) -> 'Some[_ValueType]':
120+
def rescue(self, function) -> 'Some[_ValueType]':
121121
...
122122

123123
def value_or(self, default_value: _NewValueType) -> _ValueType:

0 commit comments

Comments
 (0)