@@ -4,7 +4,7 @@ Container: the concept
4
4
.. currentmodule :: returns.primitives.container
5
5
6
6
Container is a concept that allows you
7
- to write code without traditional error handling
7
+ to write code around the existing wrapped values
8
8
while maintaining the execution context.
9
9
10
10
We will show you its simple API of one attribute and several simple methods.
15
15
16
16
The main idea behind a container is that it wraps some internal state.
17
17
That's what
18
- :py:attr: `_inner_value <returns.primitives.container.Container._inner_value> `
18
+ :py:attr: `. _inner_value <returns.primitives.container.Container._inner_value> `
19
19
is used for.
20
20
21
21
And we have several functions
@@ -32,10 +32,61 @@ And we can see how this state is evolving during the execution.
32
32
F4 --> F5["Container(SentNotificationId(992))"]
33
33
34
34
35
+ Working with containers
36
+ -----------------------
37
+
38
+ We use two methods to create new containers from the previous one.
39
+ ``bind `` and ``map ``.
40
+
41
+ The difference is simple:
42
+
43
+ - ``map `` works with functions that return regular values
44
+ - ``bind `` works with functions that return other containers of the same type
45
+
46
+ :func: `.bind <returns.primitives.container.Container.bind> `
47
+ is used to literally bind two different containers together.
48
+
49
+ .. code :: python
50
+
51
+ from returns.result import Result, Success
52
+
53
+ def may_fail (user_id : int ) -> Result[int , str ]:
54
+ ...
55
+
56
+ result = Success(1 ).bind(may_fail)
57
+ # => Will be equal to either Success[int] or Failure[str]
58
+
59
+ And we use :func: `.map <returns.primitives.container.Container.map> `
60
+ to use containers with regular functions.
61
+
62
+ .. code :: python
63
+
64
+ from returns.result import Success
65
+
66
+ def double (state : int ) -> int :
67
+ return state * 2
68
+
69
+ result = Success(1 ).map(double)
70
+ # => Will be equal to Success(2)
71
+
72
+ The same work with built-in functions as well:
73
+
74
+ .. code :: python
75
+
76
+ from returns.io import IO
77
+
78
+ IO(' bytes' ).map(list )
79
+ # => <IO: ['b', 'y', 't', 'e', 's']>
80
+
81
+ Note::
82
+
83
+ All containers support these methods.
84
+
85
+
35
86
Railway oriented programming
36
87
----------------------------
37
88
38
- We use a concept of
89
+ When talking about error handling we use a concept of
39
90
`Railway oriented programming <https://fsharpforfunandprofit.com/rop/ >`_.
40
91
It mean that our code can go on two tracks:
41
92
@@ -73,62 +124,16 @@ or we can rescue the situation.
73
124
style F6 fill:red
74
125
style F8 fill:red
75
126
76
-
77
-
78
- Working with containers
79
- -----------------------
80
-
81
- We use two methods to create new containers from the previous one.
82
- ``bind `` and ``map ``.
83
-
84
- The difference is simple:
85
-
86
- - ``map `` works with functions that return regular values
87
- - ``bind `` works with functions that return other containers
88
-
89
- :func: `Container.bind <returns.primitives.container.Container.bind> `
90
- is used to literally bind two different containers together.
91
-
92
- .. code :: python
93
-
94
- from returns.result import Result, Success
95
-
96
- def make_http_call (user_id : int ) -> Result[int , str ]:
97
- ...
98
-
99
- result = Success(1 ).bind(make_http_call)
100
- # => Will be equal to either Success[int] or Failure[str]
101
-
102
- So, the rule is: whenever you have some impure functions,
103
- it should return a container type instead.
104
-
105
- And we use :func: `Container.map <returns.primitives.container.Container.map> `
106
- to use containers with `pure functions <https://en.wikipedia.org/wiki/Pure_function >`_.
107
-
108
- .. code :: python
109
-
110
- from returns.result import Success
111
-
112
- def double (state : int ) -> int :
113
- return state * 2
114
-
115
- result = Success(1 ).map(double)
116
- # => Will be equal to Success(2)
117
-
118
- Note::
119
-
120
- All containers support these methods.
121
-
122
127
Returning execution to the right track
123
128
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124
129
125
130
We also support two special methods to work with "failed"
126
- types like ``Failure `` and `` Nothing `` :
131
+ types like ``Failure ``:
127
132
128
- - :func: `Container .fix <returns.primitives.container.Container .fix> `
133
+ - :func: `.fix <returns.primitives.container.FixableContainer .fix> `
129
134
is the opposite of ``map `` method
130
135
that works only when container is in failed state
131
- - :func: `Container .rescue <returns.primitives.container.Container .rescue> `
136
+ - :func: `.rescue <returns.primitives.container.FixableContainer .rescue> `
132
137
is the opposite of ``bind `` method
133
138
that works only when container is in failed state
134
139
@@ -145,20 +150,23 @@ during the pipeline execution:
145
150
Failure(1 ).fix(double)
146
151
# => Will be equal to Success(2.0)
147
152
148
- ``rescue `` can return any container type you want .
149
- It can also fix your flow and get on the successful track again:
153
+ ``rescue `` should return one of `` Success `` or `` Failure `` types .
154
+ It can also rescue your flow and get on the successful track again:
150
155
151
156
.. code :: python
152
157
153
158
from returns.result import Result, Failure, Success
154
159
155
- def fix (state : Exception ) -> Result[int , Exception ]:
160
+ def tolerate_exception (state : Exception ) -> Result[int , Exception ]:
156
161
if isinstance (state, ZeroDivisionError ):
157
162
return Success(0 )
158
163
return Failure(state)
159
164
160
- Failure(ZeroDivisionError ).rescue(fix)
161
- # => Will be equal to Success(0)
165
+ Failure(ZeroDivisionError ()).rescue(tolerate_exception)
166
+ # => Success(0)
167
+
168
+ Failure(ValueError ()).rescue(tolerate_exception)
169
+ # => Failure(ValueError())
162
170
163
171
Note::
164
172
@@ -171,9 +179,9 @@ Unwrapping values
171
179
And we have two more functions to unwrap
172
180
inner state of containers into a regular types:
173
181
174
- - :func: `Container .value_or <returns.primitives.container.Container .value_or> `
182
+ - :func: `.value_or <returns.primitives.container.ValueUnwrapContainer .value_or> `
175
183
returns a value if it is possible, returns ``default_value `` otherwise
176
- - :func: `Container .unwrap <returns.primitives.container.Container .unwrap> `
184
+ - :func: `.unwrap <returns.primitives.container.ValueUnwrapContainer .unwrap> `
177
185
returns a value if it is possible, raises ``UnwrapFailedError `` otherwise
178
186
179
187
.. code :: python
@@ -195,7 +203,7 @@ inner state of containers into a regular types:
195
203
The most user-friendly way to use ``unwrap `` method is with :ref: `pipeline `.
196
204
197
205
For failing containers you can
198
- use :func: `Container .failure <returns.primitives.container.Container .failure> `
206
+ use :func: `.failure <returns.primitives.container.FixableContainer .failure> `
199
207
to unwrap the failed state:
200
208
201
209
.. code :: python
0 commit comments