@@ -112,12 +112,12 @@ that implements the ``Mappable`` interface:
112112 >> > maybe_str: Maybe[str ] = Some(' example' )
113113 >> > assert maybe_str.map(can_be_mapped) == Some(' example!' )
114114
115- :class: `~returns.interfaces.mappable. MappableN ` interface help us to
115+ :class: `~MappableN ` interface helps us to
116116create our own mappable container like :class: `~returns.maybe.Maybe `.
117117
118118.. code :: python
119119
120- >> > from typing import Any, Callable, TypeVar
120+ >> > from typing import Callable, TypeVar
121121
122122 >> > from returns.interfaces.mappable import Mappable1
123123 >> > from returns.primitives.hkt import SupportsKind1
@@ -154,12 +154,12 @@ With our ``Number`` mappable class we can compose easily math functions with it.
154154 Laws
155155~~~~
156156
157- To make sure your mappable implementation is right, you can apply the
158- Mappable laws on it to test.
157+ To make sure your `` Mappable `` implementation is right,
158+ you can apply the `` Mappable `` laws on it to test.
159159
1601601. :func: `Identity Law <_LawSpec.identity_law> `:
161- When we pass the identity function to the map method,
162- the mappable has to be the same, unaltered .
161+ When we pass the identity function to the `` map `` method,
162+ the `` Mappable `` instance has to be the same, unchanged .
163163
164164.. code :: python
165165
@@ -201,44 +201,282 @@ Bindable
201201
202202Bindable is something that we can bind with a function. Like
203203:class: `~returns.maybe.Maybe `, so
204- :class: `~returns.interfaces.bindable. BindableN ` interface will help
204+ :class: `~BindableN ` interface will help
205205us to create our custom bindable.
206206
207207.. code :: python
208208
209- >> > from dataclasses import dataclass
210- >> > from typing import Any, Callable, TypeVar
209+ >> > from typing import Callable, TypeVar
211210
212211 >> > from returns.interfaces.bindable import Bindable1
213- >> > from returns.primitives.hkt import SupportsKind1
212+ >> > from returns.primitives.hkt import SupportsKind1, Kind1, dekind
214213 >> > from returns.primitives.container import BaseContainer
215214
216- >> > _BagContentType = TypeVar(' _BagContentType ' )
217- >> > _NewBagContentType = TypeVar(' _NewBagContentType ' )
215+ >> > _NumberType = TypeVar(' _NumberType ' )
216+ >> > _NewNumberType = TypeVar(' _NewNumberType ' )
218217
219- >> > class Bag (
218+ >> > class Number (
220219 ... BaseContainer ,
221- ... SupportsKind1[' Bag ' , int ],
222- ... Bindable1[_BagContentType ],
220+ ... SupportsKind1[' Number ' , _NumberType ],
221+ ... Bindable1[_NumberType ],
223222 ... ):
224- ... def __init__ (self , inner_value : _BagContentType ) -> None :
223+ ... def __init__ (self , inner_value : _NumberType ) -> None :
225224 ... super ().__init__ (inner_value)
226225 ...
227- ... def bind (
226+ ... def bind ( # This method is required by Bindable
228227 ... self ,
229- ... function : Callable[[_BagContentType], ' Bag[_NewBagContentType]' ]
230- ... ) -> ' Bag[_NewBagContentType]' :
231- ... return function(self ._inner_value)
228+ ... function : Kind1[
229+ ... ' Number' ,
230+ ... Callable[[_NumberType], ' Number[_NewNumberType]' ],
231+ ... ],
232+ ... ) -> ' Number[_NewNumberType]' :
233+ ... return dekind(function(self ._inner_value))
234+
235+ And here's how we can use it:
236+
237+ .. code :: python
238+
239+ >> > def double (arg : int ) -> Number[int ]:
240+ ... return Number(arg * 2 )
241+
242+ >> > number = Number(5 )
243+ >> > assert number.bind(double) == Number(10 )
244+
245+
246+ Applicative
247+ -----------
248+
249+ .. currentmodule :: returns.interfaces.applicative
250+
251+ Something is considered applicative
252+ if it is a functor already and,
253+ moreover, we can ``apply `` another container to it
254+ and construct a new value with ``.from_value `` method.
232255
233- >> > @ dataclass
234- ... class Peanuts (object ):
235- ... quantity: int
256+ An example in this library is :class: `~returns.maybe.Maybe `,
257+ that implements the ``Mappable `` and ``Applicative `` interfaces:
258+
259+ .. code :: python
260+
261+ >> > from returns.maybe import Maybe, Some
236262
237- >> > def get_half ( peanuts : Peanuts) -> Bag[Peanuts]:
238- ... return Bag(Peanuts(peanuts.quantity // 2 ))
263+ >> > maybe_str = Maybe.from_value( ' example ' )
264+ >> > maybe_func = Maybe.from_value( len ) # we use function as a value!
239265
240- >> > bag_of_peanuts: Bag[Peanuts] = Bag(Peanuts(10 ))
241- >> > assert bag_of_peanuts.bind(get_half) == Bag(Peanuts(5 ))
266+ >> > assert maybe_str.apply(maybe_func) == Some(7 )
267+
268+ As you see, ``apply `` takes a container with a function inside
269+ and applies it to the currect value inside the container.
270+
271+ This way we really execute ``Maybe.from_value(len('example')) ``.
272+
273+ :class: `~ApplicativeN ` which is a subtype of
274+ :class: `~returns.interfaces.mappable.MappableN ` interface helps us to
275+ create our own applicative container like :class: `~returns.maybe.Maybe `.
276+
277+ .. code :: python
278+
279+ >> > from typing import Callable, TypeVar
280+
281+ >> > from returns.interfaces.applicative import Applicative1
282+ >> > from returns.primitives.hkt import SupportsKind1, Kind1, dekind
283+ >> > from returns.primitives.container import BaseContainer
284+
285+ >> > _NumberType = TypeVar(' _NumberType' )
286+ >> > _NewNumberType = TypeVar(' _NewNumberType' )
287+
288+ >> > class Number (
289+ ... BaseContainer ,
290+ ... SupportsKind1[' Number' , _NumberType],
291+ ... Applicative1[_NumberType],
292+ ... ):
293+ ... def __init__ (self , inner_value : _NumberType) -> None :
294+ ... super ().__init__ (inner_value)
295+ ...
296+ ... def map ( # This method is required by Mappable
297+ ... self ,
298+ ... function : Callable[[_NumberType], _NewNumberType]
299+ ... ) -> ' Number[_NewNumberType]' :
300+ ... return Number(function(self ._inner_value))
301+ ...
302+ ... def apply ( # This method is required by Applicative
303+ ... self ,
304+ ... container : Kind1[
305+ ... ' Number' ,
306+ ... Callable[[_NumberType], _NewNumberType],
307+ ... ],
308+ ... ) -> ' Number[_NewNumberType]' :
309+ ... return Number.from_value(
310+ ... dekind(container._inner_value(self ._inner_value)),
311+ ... )
312+ ...
313+ ... @ classmethod
314+ ... def from_value ( # This method is required by Applicative
315+ ... cls ,
316+ ... inner_value : _NewNumberType,
317+ ... ) -> ' Number[_NewNumberType]' :
318+ ... return Number(inner_value)
319+
320+ With our ``Number `` mappable class we can compose easily math functions with it.
321+
322+ .. code :: python
323+
324+ >> > def my_math_function (number : int ) -> int :
325+ ... return number - 1
326+
327+ >> > number = Number(3 )
328+ >> > number_function = Number.from_value(my_math_function)
329+
330+ >> > assert number.apply(number_function) == Number(2 )
331+
332+ Laws
333+ ~~~~
334+
335+ To make sure your ``Applicative `` implementation is right,
336+ you can apply the ``Applicative `` laws on it to test.
337+
338+ 1. :func: `Identity Law <_LawSpec.identity_law> `:
339+ When we pass an applicative instance
340+ with wrapped identity function to the ``apply `` method,
341+ the ``Applicative `` has to be the same, unchanged.
342+
343+ .. code :: python
344+
345+ >> > from returns.functions import identity
346+
347+ >> > applicative_number: Number[int ] = Number(1 )
348+ >> > assert applicative_number.apply(
349+ ... applicative_number.from_value(identity),
350+ ... ) == Number(1 )
351+
352+ 2. :func: `Interchange Law <_LawSpec.interchange_law> `:
353+ We can start our composition with both raw value and a function.
354+
355+ .. code :: python
356+
357+ >> > def function (arg : int ) -> int :
358+ ... return arg + 1
359+
360+ >> > raw_value = 5
361+
362+ >> > assert Number.from_value(raw_value).apply(
363+ ... Number.from_value(function),
364+ ... ) == Number.from_value(function).apply(
365+ ... Number.from_value(lambda inner : inner(raw_value)),
366+ ... )
367+
368+ 3. :func: `Homomorphism Law <_LawSpec.homomorphism_law> `:
369+ The homomorphism law says that
370+ applying a wrapped function to a wrapped value is the same
371+ as applying the function to the value in the normal way
372+ and then using ``.from_value `` on the result.
373+
374+ .. code :: python
375+
376+ >> > def function (arg : int ) -> int :
377+ ... return arg + 1
378+
379+ >> > raw_value = 5
380+
381+ >> > assert Number.from_value(
382+ ... function(raw_value),
383+ ... ) == Number.from_value(raw_value).apply(
384+ ... Number.from_value(function),
385+ ... )
386+
387+ 4. :func: `Composition Law <_LawSpec.composition_law> `:
388+ Appling two functions twice is the same
389+ as applying their composition once.
390+
391+ .. code :: python
392+
393+ >> > from returns.functions import compose
394+
395+ >> > def first (arg : int ) -> int :
396+ ... return arg * 2
397+
398+ >> > def second (arg : int ) -> int :
399+ ... return arg + 1
400+
401+ >> > instance = Number(5 )
402+ >> > assert instance.apply(
403+ ... Number.from_value(compose(first, second)),
404+ ... ) == instance.apply(
405+ ... Number.from_value(first),
406+ ... ).apply(
407+ ... Number.from_value(second),
408+ ... )
409+
410+ Plus all laws from ``MappableN `` interface.
411+
412+
413+ Container
414+ ---------
415+
416+ .. currentmodule :: returns.interfaces.container
417+
418+ :class: `~ContainerN ` is a central piece of our library.
419+ It is an interface that combines
420+ :class: `~returns.interfaces.applicative.ApplicativeN `
421+ and
422+ :class: `~returns.interfaces.bindable.BindableN ` together.
423+
424+ So, in other words: ``Container `` is an ``Apllicative `` that you can ``bind ``!
425+
426+ .. code :: python
427+
428+ >> > from typing import Callable, TypeVar
429+
430+ >> > from returns.interfaces.container import Container1
431+ >> > from returns.primitives.hkt import SupportsKind1, Kind1, dekind
432+ >> > from returns.primitives.container import BaseContainer
433+
434+ >> > _NumberType = TypeVar(' _NumberType' )
435+ >> > _NewNumberType = TypeVar(' _NewNumberType' )
436+
437+ >> > class Number (
438+ ... BaseContainer ,
439+ ... SupportsKind1[' Number' , _NumberType],
440+ ... Container1[_NumberType],
441+ ... ):
442+ ... def __init__ (self , inner_value : _NumberType) -> None :
443+ ... super ().__init__ (inner_value)
444+ ...
445+ ... def map ( # This method is required by Mappable
446+ ... self ,
447+ ... function : Callable[[_NumberType], _NewNumberType]
448+ ... ) -> ' Number[_NewNumberType]' :
449+ ... return Number(function(self ._inner_value))
450+ ...
451+ ... def bind ( # This method is required by Bindable
452+ ... self ,
453+ ... function : Kind1[
454+ ... ' Number' ,
455+ ... Callable[[_NumberType], ' Number[_NewNumberType]' ],
456+ ... ],
457+ ... ) -> ' Number[_NewNumberType]' :
458+ ... return dekind(function(self ._inner_value))
459+ ...
460+ ... def apply ( # This method is required by Applicative
461+ ... self ,
462+ ... container : Kind1[
463+ ... ' Number' ,
464+ ... Callable[[_NumberType], _NewNumberType],
465+ ... ],
466+ ... ) -> ' Number[_NewNumberType]' :
467+ ... return Number.from_value(
468+ ... container._inner_value(self ._inner_value),
469+ ... )
470+ ...
471+ ... @ classmethod
472+ ... def from_value ( # This method is required by Applicative
473+ ... cls ,
474+ ... inner_value : _NewNumberType,
475+ ... ) -> ' Number[_NewNumberType]' :
476+ ... return Number(inner_value)
477+
478+ This code gives us an opportunity to use ``Number ``
479+ with ``map ``, ``apply ``, and ``bind `` as we already did in the examples above.
242480
243481Laws
244482~~~~
@@ -252,19 +490,19 @@ respect three new laws.
252490
253491.. code :: python
254492
255- >> > def can_be_bound (value : int ) -> Bag[Peanuts ]:
256- ... return Bag(Peanuts( value) )
493+ >> > def can_be_bound (value : int ) -> Number[ int ]:
494+ ... return Number( value)
257495
258- >> > assert Bag (5 ).bind(can_be_bound) == can_be_bound(5 )
496+ >> > assert Number.from_value (5 ).bind(can_be_bound) == can_be_bound(5 )
259497
260498 2. :func: `Right Identity <_LawSpec.right_identity_law> `:
261499 If we pass the bindable constructor through ``bind `` must
262500 have to be the same result as instantiating the bindable on our own.
263501
264502.. code :: python
265503
266- >> > bag = Bag(Peanuts( 2 ) )
267- >> > assert bag .bind(Bag ) == Bag(Peanuts( 2 ) )
504+ >> > number = Number( 2 )
505+ >> > assert number .bind(Number ) == Number( 2 )
268506
269507 3. :func: `Associative Law <_LawSpec.associative_law> `:
270508 Given two functions, ``x `` and ``y ``, calling the bind
@@ -275,31 +513,18 @@ respect three new laws.
275513
276514.. code :: python
277515
278- >> > def minus_one (peanuts : Peanuts ) -> Bag[Peanuts ]:
279- ... return Bag(Peanuts(peanuts.quantity - 1 ) )
516+ >> > def minus_one (arg : int ) -> Number[ int ]:
517+ ... return Number(arg - 1 )
280518
281- >> > def half (peanuts : Peanuts ) -> Bag[Peanuts ]:
282- ... return Bag(Peanuts(peanuts.quantity // 2 ) )
519+ >> > def half (arg : int ) -> Number[ int ]:
520+ ... return Number(arg // 2 )
283521
284- >> > bag = Bag(Peanuts( 9 ) )
285- >> > assert bag .bind(minus_one).bind(half) == bag .bind(
522+ >> > number = Number( 9 )
523+ >> > assert number .bind(minus_one).bind(half) == number .bind(
286524 ... lambda value : minus_one(value).bind(half),
287525 ... )
288526
289-
290- Applicative
291- -----------
292-
293- .. currentmodule :: returns.interfaces.applicative
294-
295- Laws
296- ~~~~
297-
298-
299- Container
300- ---------
301-
302- .. currentmodule :: returns.interfaces.container
527+ Plus all laws from ``MappableN `` and ``ApplicativeN `` interfaces.
303528
304529
305530More!
0 commit comments