1
1
Container: the concept
2
2
======================
3
3
4
- .. currentmodule :: returns.primitives.monads
5
-
6
- We won't say that monad is `a monoid in the category of endofunctors <https://stackoverflow.com/questions/3870088/a-monad-is-just-a-monoid-in-the-category-of-endofunctors-whats-the-problem >`_.
4
+ .. currentmodule :: returns.primitives.container
7
5
8
6
Container is a concept that allows you
9
7
to write code without traditional error handling
@@ -14,12 +12,13 @@ We will show you its simple API of one attribute and several simple methods.
14
12
Internals
15
13
---------
16
14
17
- The main idea behind a monad is that it wraps some internal state.
15
+ The main idea behind a container is that it wraps some internal state.
18
16
That's what
19
- :py:attr: `Container. _inner_value <returns.primitives.monad .Container._inner_value> `
17
+ :py:attr: `_inner_value <returns.primitives.container .Container._inner_value> `
20
18
is used for.
21
19
22
- And we have several functions to create new monads based on the previous state.
20
+ And we have several functions
21
+ to create new containers based on the previous state.
23
22
And we can see how this state is evolving during the execution.
24
23
25
24
.. mermaid ::
@@ -31,19 +30,19 @@ And we can see how this state is evolving during the execution.
31
30
F3 --> F4["State(FailedLoginAttempt(1))"]
32
31
F4 --> F5["State(SentNotificationId(992))"]
33
32
34
- Creating new monads
35
- ~~~~~~~~~~~~~~~~~~~
33
+ Creating new containers
34
+ ~~~~~~~~~~~~~~~~~~~~~~~
36
35
37
- We use two methods to create new monads from the previous one.
36
+ We use two methods to create new containers from the previous one.
38
37
``bind `` and ``map ``.
39
38
40
39
The difference is simple:
41
40
42
41
- ``map `` works with functions that return regular values
43
- - ``bind `` works with functions that return monads
42
+ - ``bind `` works with functions that return containers
44
43
45
- :func: `Container.bind <returns.primitives.monad .Container.bind> `
46
- is used to literally bind two different monads together.
44
+ :func: `Container.bind <returns.primitives.container .Container.bind> `
45
+ is used to literally bind two different containers together.
47
46
48
47
.. code :: python
49
48
@@ -56,10 +55,10 @@ is used to literally bind two different monads together.
56
55
# => Will be equal to Result Success[int] or Failure[str]
57
56
58
57
So, the rule is: whenever you have some impure functions,
59
- it should return a monad instead.
58
+ it should return a container type instead.
60
59
61
- And we use :func: `Container.map <returns.primitives.monad .Container.map> `
62
- to use monads with pure functions.
60
+ And we use :func: `Container.map <returns.primitives.container .Container.map> `
61
+ to use containers with ` pure functions < https://en.wikipedia.org/wiki/Pure_function >`_ .
63
62
64
63
.. code :: python
65
64
@@ -75,12 +74,14 @@ Reverse operations
75
74
~~~~~~~~~~~~~~~~~~
76
75
77
76
We also support two special methods to work with "failed"
78
- monads like ``Failure `` and ``Nothing ``:
77
+ types like ``Failure `` and ``Nothing ``:
79
78
80
- - :func: `Container.fix <returns.primitives.monad.Container.fix> ` the opposite
81
- of ``map `` method that works only when monad is failed
82
- - :func: `Container.rescue <returns.primitives.monad.Container.rescue> ` the opposite
83
- of ``bind `` method that works only when monad is failed
79
+ - :func: `Container.fix <returns.primitives.container.Container.fix> `
80
+ is the opposite of ``map `` method
81
+ that works only when container is in failed state
82
+ - :func: `Container.rescue <returns.primitives.container.Container.rescue> `
83
+ is the opposite of ``bind `` method
84
+ that works only when container is in failed state
84
85
85
86
``fix `` can be used to fix some fixable errors
86
87
during the pipeline execution:
@@ -95,8 +96,8 @@ during the pipeline execution:
95
96
Failure(1 ).fix(double)
96
97
# => Will be equal to Success(2.0)
97
98
98
- ``rescue `` can return any monad you want.
99
- It can also fix your flow and get on the Success track again:
99
+ ``rescue `` can return any container type you want.
100
+ It can also fix your flow and get on the successful track again:
100
101
101
102
.. code :: python
102
103
@@ -114,12 +115,12 @@ Unwrapping values
114
115
~~~~~~~~~~~~~~~~~
115
116
116
117
And we have two more functions to unwrap
117
- inner state of monads into a regular types:
118
+ inner state of containers into a regular types:
118
119
119
- - :func: `Container.value_or <returns.primitives.monad .Container.value_or> ` - returns
120
- a value if it is possible, returns ``default_value `` otherwise
121
- - :func: `Container.unwrap <returns.primitives.monad .Container.unwrap> ` - returns
122
- a value if it possible, raises ``UnwrapFailedError `` otherwise
120
+ - :func: `Container.value_or <returns.primitives.container .Container.value_or> `
121
+ returns a value if it is possible, returns ``default_value `` otherwise
122
+ - :func: `Container.unwrap <returns.primitives.container .Container.unwrap> `
123
+ returns a value if it is possible, raises ``UnwrapFailedError `` otherwise
123
124
124
125
.. code :: python
125
126
@@ -139,9 +140,9 @@ inner state of monads into a regular types:
139
140
140
141
The most user-friendly way to use ``unwrap `` method is with :ref: `do-notation `.
141
142
142
- For failing monads you can
143
- use :func: `Container.failure <returns.primitives.monad .Container.failure> `
144
- to unwrap failed state:
143
+ For failing containers you can
144
+ use :func: `Container.failure <returns.primitives.container .Container.failure> `
145
+ to unwrap the failed state:
145
146
146
147
.. code :: python
147
148
@@ -152,16 +153,16 @@ to unwrap failed state:
152
153
# => Traceback (most recent call last): UnwrapFailedError
153
154
154
155
Be careful, since this method will raise an exception
155
- when you try to ``failure `` a successful monad .
156
+ when you try to ``failure `` a successful container .
156
157
157
158
Immutability
158
159
------------
159
160
160
161
We like to think of ``returns `` as immutable structures.
161
- You cannot mutate the inner state of the created monad ,
162
+ You cannot mutate the inner state of the created container ,
162
163
because we redefine ``__setattr__ `` and ``__delattr__ `` magic methods.
163
164
164
- You cannot also set new attributes to monad instances,
165
+ You cannot also set new attributes to container instances,
165
166
since we are using ``__slots__ `` for better performance and strictness.
166
167
167
168
Well, nothing is **really ** immutable in python, but you were warned.
@@ -178,7 +179,7 @@ So, instead of:
178
179
179
180
.. code :: python
180
181
181
- some_monad .map(lambda x : x + 2 ) # : Callable[[Any], Any]
182
+ some_container .map(lambda x : x + 2 ) # : Callable[[Any], Any]
182
183
183
184
Write:
184
185
@@ -189,7 +190,7 @@ Write:
189
190
def increment (addition : int , number : int ) -> int :
190
191
return number + addition
191
192
192
- some_monad .map(partial(increment, 2 )) # : functools.partial[builtins.int* ]
193
+ some_container .map(partial(increment, 2 )) # functools.partial[builtins.int]
193
194
194
195
This way your code will be type-safe from errors.
195
196
0 commit comments