Dependency injection is a popular software architechture pattern.
It’s main idea is that you provide Inversion of Control and can pass different things into your logic instead of hardcoding you stuff. And by doing this you are on your way to achieve Single Responsibility for your functions and objects.
A lot of programms we write rely on the context implicitly or explicitly. We can rely on confugration, env variables, stubs, logical dependencies, etc.
Let’s look at the example.
One of the most popular errors Python developers do in Django
is that they overuse settings
object inside the business logic.
This makes your logic framework-oriented
and hard to reason about in large projects.
Because values just pop out of nowhere in a deeply nested functions. And can be changed from the outside, from the context of your app.
Imagine that you have a django
based game,
where you award users with points
for each guessed letter in a word (unguessed letters are marked as '.'
):
from django.http import HttpRequest, HttpResponse
from words_app.logic import calculate_points
def view(request: HttpRequest) -> HttpResponse:
user_word: str = request.POST['word'] # just an example
points = calculate_points(user_word)
... # later you show the result to user somehow
# Somewhere in your `words_app/logic.py`:
def calculate_points(word: str) -> int:
guessed_letters_count = len([letter for letter in word if letter != '.'])
return _award_points_for_letters(guessed_letters_count)
def _award_points_for_letters(guessed: int) -> int:
return 0 if guessed < 5 else guessed # minimum 6 points possible!
Straight and simple!
But, later you decide to make the game more fun: let’s make the minimal accoutable letters threshold configurable for an extra challenge.
You can just do it directly:
def _award_points_for_letters(guessed: int, threshold: int) -> int:
return 0 if guessed < threshold else guessed
And now your code won’t simply type-check. Because that’s how our caller looks like:
def calculate_points(word: str) -> int:
guessed_letters_count = len([letter for letter in word if letter != '.'])
return _award_points_for_letters(guessed_letters_count)
To fix this calculate_points
function
(and all other upper caller functions)
will have to accept threshold: int
as a parameter and pass it to _award_points_for_letters
.
Imagine that your large project has multiple things to configure in multiple functions. What a mess it would be!
Ok, you can directly use django.settings
(or similar)
in your _award_points_for_letters
function.
And ruin your pure logic with framework-specific details. That’s ugly!
We have learned that this tiny change showed us that it is not so easy to rely on implicit app context.
And instead of passing parameters for all callstack
or using dirty framework specific magic
you can use RequiresContext
container.
That was built just for this case.
Let’s see how our code changes:
from django.conf import settings
from django.http import HttpRequest, HttpResponse
from words_app.logic import calculate_points
def view(request: HttpRequest) -> HttpResponse:
user_word: str = request.POST['word'] # just an example
points = calculate_points(user_words)(settings) # passing the dependencies
... # later you show the result to user somehow
# Somewhere in your `words_app/logic.py`:
from typing_extensions import Protocol
from returns.context import RequiresContext
class _Deps(Protocol): # we rely on abstractions, not direct values or types
WORD_THRESHOLD: int
def calculate_points(word: str) -> RequiresContext[_Deps, int]:
guessed_letters_count = len([letter for letter in word if letter != '.'])
return _award_points_for_letters(guessed_letters_count)
def _award_points_for_letters(guessed: int) -> RequiresContext[_Deps, int]:
return RequiresContext(
lambda deps: 0 if guessed < deps.WORD_THRESHOLD else guessed,
)
And now you can pass your dependencies in a really direct and explicit way.
Let’s try to configure how we mark our unguessed letters
(previously unguessed letters were marked as '.'
).
Let’s say, we want to change this to be _
.
How can we do that with our existing function?
def calculate_points(word: str) -> RequiresContext[_Deps, int]:
guessed_letters_count = len([letter for letter in word if letter != '.'])
return _award_points_for_letters(guessed_letters_count)
We are already using RequiresContext
,
but its dependencies are just hidden from us!
We have a special helper for this case: returns.context.Context.ask()
,
which returns us current dependencies.
The only thing we need to is to properly
annotate the type for our case: Context[_Deps].ask()
Sadly, currently mypy
is not able to infer the dependency type
out of the context and we need to explicitly provide it.
Let’s see the final result:
from returns.context import Context, RequiresContext
class _Deps(Protocol): # we rely on abstractions, not direct values or types
WORD_THRESSHOLD: int
UNGUESSED_CHAR: str
def calculate_points(word: str) -> RequiresContext[_Deps, int]:
def factory(deps: _Deps) -> RequiresContext[_Deps, int]:
guessed_letters_count = len([
letter for letter in word if letter != deps.UNGUESSED_CHAR
])
return _award_points_for_letters(guessed_letters_count)
return Context[_Deps].ask().bind(factory)
And now we access the current context from any place in our callstack. Isn’t it convenient?
The concept behind RequiresContext
container is really simple.
It is a container around Callable[[EnvType], ReturnType]
function.
By its definition it works with pure functions that never fails.
It can be illustrated as a simple nested function:
>>> from typing import Callable
>>> def first(limit: int) -> Callable[[str], bool]:
... def inner(deps: str) -> bool:
... return len(deps) > limit
... return inner
...
>>> first(2)('abc') # first(arg1)(dependencies)
True
>>> first(5)('abc') # first(arg1)(dependencies)
False
That’s basically enough to make dependency injection possible.
But how would you compose first
function?
Let’s say with the following function:
>>> def bool_to_str(arg: bool) -> str:
... return 'ok' if arg else 'nope'
...
It would be hard, knowing that it returns another function to be called later when the context is known.
We can wrap it in RequiresContext
container to allow better composition!
>>> from returns.context import RequiresContext
>>> def first(limit: int) -> RequiresContext[str, bool]:
... def inner(deps: str) -> bool:
... return len(deps) > limit
... return RequiresContext(inner) # wrapping function here!
...
>>> first(1).map(bool_to_str)('abc')
'ok'
>>> first(5).map(bool_to_str)('abc')
'nope'
There’s how execution flows:
The rule is: the dependencies are injected at the very last moment in time. And then normal logical execution happens.
This container is a combintaion of RequiresContext[env, Result[a, b]]
.
Which means that it is a wrapper around pure function that might fail.
We also added a lot of useful methods for this container, so you can work easily with it:
from_typecast()
turns accidental RequiresContext[env, Result[a, b]]
into
full-featured RequiresContextResult[env, a, b]
bind_result()
allows to bind functions that return Result
with just one call
bind_context()
allows to bind functions that return RequiresContext
easily
There are also several useful contructors from any possible type
Use it when you work with pure context-related functions that might fail.
This container is a combintaion of RequiresContext[env, IOResult[a, b]]
.
Which means that it is a wrapper around impure function that might fail.
We also added a lot of useful methods for this container, so you can work easily with it:
from_typecast()
turns accidental RequiresContext[env, IOResult[a, b]]
into
full-featured RequiresContextIOResult[env, a, b]
bind_result()
allows to bind functions that return Result
with just one call
bind_ioresult()
allows to bind functions that return IOResult
with just one call
bind_context()
allows to bind functions that return RequiresContext
easily
bind_context_result()
allows to bind functions that return RequiresContextResult
easily
There are also several useful contructors from any possible type
Use it when you work with impure context-related functions that might fail. This is basically the main type that is going to be used in most apps.
There are several useful alises for RequiresContext
and friends with some common values:
returns.context.requires_context_result.ReaderResult
is an alias for RequiresContextResult[...]
to save you some typing.
Uses Reader
because it is a native name for this concept from Haskell.
returns.result.requires_context.ReaderResultE
is an alias for RequiresContextResult[..., Exception]
,
just use it when you want to work with RequiresContextResult
containers
that use exceptions as error type.
It is named ResultE
because it is ResultException
and ResultError
at the same time.
returns.context.requires_context_io_result.ReaderIOResult
is an alias for RequiresContextIOResult[...]
to save you some typing.
Uses Reader
because it is a native name for this concept from Haskell.
returns.result.requires_context.ReaderIOResultE
is an alias for RequiresContextIOResult[..., Exception]
,
just use it when you want to work with RequiresContextIOResult
containers
that use exceptions as error type.
It is named ResultE
because it is ResultException
and ResultError
at the same time.
We actually can! But, it is harder to write.
And RequiresContextResult
is actually
the very same thing as RequiresContext[e, Result]
, but has nicer API:
x: RequiresContext[int, Result[int, str]]
x.map(lambda result: result.map(lambda number: number + 1))
# Is the same as:
y: RequiresContextResult[int, int, str]
y.map(lambda number: number + 1)
The second one looks better, doesn’t it?
The same applies for RequiresContextIOResult
as well.
RequiresContext
allows you to create
unit values with the help of .from_value
method:
>>> from returns.context import RequiresContext
>>> assert RequiresContext.from_value(1)(...) == 1
RequiresContextResult
requires you to use one of the following methods:
from_success
when you want to mark some raw value as a Success
from_failure
when you want to mark some raw value as a Failure
from_result
when you already have one
from_successful_context
when you have successful RequiresContext
from_failed_context
when you have failed RequiresContext
But, think twice: why would you need to do it? These classes represent computations that rely on context. Maybe, you should not do creat their units?
RequiresContextIOResult
requires you to use one of the following methods:
from_success
when you want to mark some raw value as a Success
from_failure
when you want to mark some raw value as a Failure
from_result
when you already have Result
container
from_ioresult
when you already have IOResult
container
from_successful_context
when you have successful RequiresContext
from_failed_context
when you have failed RequiresContext
Because mypy
cannot possibly know the type of current context.
This is hard even for a plugin.
So, using this technique is better:
from returns.context import Context, RequiresContext
def some_context(*args, **kwargs) -> RequiresContext[int, str]:
def factory(deps: int) -> RequiresContext[int, str]:
...
return Context[int].ask().bind(factory)
RequiresContext
(inner_value)[source]¶Bases: returns.primitives.container.BaseContainer
, typing.Generic
The RequiresContext
container.
It’s main purpose is to wrap some specific function and give tools to compose other functions around it without the actual calling it.
The RequiresContext
container pass the state
you want to share between functions.
Functions may read that state, but can’t change it.
The RequiresContext
container
lets us access shared immutable state within a specific context.
It can be used for lazy evaluation and typed dependency injection.
RequiresContext
is used with functions that never fails.
If you want to use RequiresContext
with returns Result
than consider using RequiresContextResult
instead.
Note
This container does not wrap ANY value. It wraps only functions. You won’t be able to supply arbitarry types!
See also
https://dev.to/gcanti/getting-started-with-fp-ts-reader-1ie5 https://en.wikipedia.org/wiki/Lazy_evaluation https://bit.ly/2R8l4WK
empty
= <object object>¶A convinient placeholder to call methods created by .from_value():
map
(function)[source]¶Allows to compose functions inside the wrapped container.
Here’s how it works:
>>> from returns.context import RequiresContext
>>> def first(lg: bool) -> RequiresContext[float, int]:
... # `deps` has `float` type here:
... return RequiresContext(
... lambda deps: deps if lg else -deps,
... )
...
>>> first(True).map(lambda number: number * 10)(2.5)
25.0
>>> first(False).map(lambda number: number * 10)(0.1)
-1.0
RequiresContext
[-_EnvType, ~_NewReturnType]
bind
(function)[source]¶Composes a container with a function returning another container.
This is useful when you do several computations that relies on the same context.
>>> from returns.context import RequiresContext
>>> def first(lg: bool) -> RequiresContext[float, int]:
... # `deps` has `float` type here:
... return RequiresContext(
... lambda deps: deps if lg else -deps,
... )
...
>>> def second(number: int) -> RequiresContext[float, str]:
... # `deps` has `float` type here:
... return RequiresContext(
... lambda deps: '>=' if number >= deps else '<',
... )
...
>>> first(True).bind(second)(1)
'>='
>>> first(False).bind(second)(2)
'<'
RequiresContext
[-_EnvType, ~_NewReturnType]
lift
(function)[source]¶Lifts function to be wrapped in a container for better composition.
In other words, it modifies the function’s
signature from: a -> b
to:
RequiresContext[env, a] -> RequiresContext[env, b]
Works similar to map()
,
but has inverse semantics.
This is how it should be used:
>>> from returns.context import RequiresContext
>>> def example(argument: int) -> float:
... return argument / 2
...
>>> container = RequiresContext.lift(example)(
... RequiresContext.from_value(2),
... )
>>> container(RequiresContext.empty)
1.0
See also
Callable
[[RequiresContext
[-_EnvType, +_ReturnType]], RequiresContext
[-_EnvType, ~_NewReturnType]]
from_value
(inner_value)[source]¶Used to return some specific value from the container.
Consider this method as a some kind of factory.
Passed value will be a return type.
Make sure to use empty
for getting the unit value.
>>> from returns.context import RequiresContext
>>> unit = RequiresContext.from_value(5)
>>> assert unit(RequiresContext.empty) == 5
Might be used with or without direct type hint.
Part of the returns.primitives.interfaces.Instanceable
protocol.
RequiresContext
[Any
, ~_FirstType]
Context
[source]¶Bases: returns.primitives.types.Immutable
, typing.Generic
Helpers that can be used to work with RequiresContext
container.
Some of them requires explicit type to be specified.
This class contains methods that do require to explicitly set type annotations. Why? Because it is impossible to figure out type without them.
So, here’s how you should use them:
Context[Dict[str, str]].ask()
Otherwise, your .ask()
method
will return RequiresContext[<nothing>, <nothing>]
,
which is unsable:
env = Context.ask()
env(some_deps)
And mypy
will warn you: error: Need type annotation for 'a'
ask
()[source]¶Get current context to use the depedencies.
It is a common scenarion when you need to use the environment.
For example, you want to do some context-related computation,
but you don’t have the context instance at your disposal.
That’s where .ask()
becomes useful!
>>> from typing_extensions import TypedDict
>>> class Deps(TypedDict):
... message: str
...
>>> def first(lg: bool) -> RequiresContext[Deps, int]:
... # `deps` has `Deps` type here:
... return RequiresContext(
... lambda deps: deps['message'] if lg else 'error',
... )
...
>>> def second(text: str) -> RequiresContext[int, int]:
... return first(len(text) > 3)
...
>>> assert second('abc')({'message': 'ok'}) == 'error'
>>> assert second('abcd')({'message': 'ok'}) == 'ok'
And now imagine that you have to change this 3
limit.
And you want to be able to set it via environment as well.
Ok, let’s fix it with the power of Context.ask()
!
>>> from typing_extensions import TypedDict
>>> class Deps(TypedDict):
... message: str
... limit: int # note this new field!
...
>>> def new_first(lg: bool) -> RequiresContext[Deps, int]:
... # `deps` has `Deps` type here:
... return RequiresContext(
... lambda deps: deps['message'] if lg else 'error',
... )
...
>>> def new_second(text: str) -> RequiresContext[int, int]:
... return Context[Deps].ask().bind(
... lambda deps: new_first(len(text) > deps.get('limit', 3)),
... )
...
>>> assert new_second('abc')({'message': 'ok', 'limit': 2}) == 'ok'
>>> assert new_second('abcd')({'message': 'ok'}) == 'ok'
>>> new_second('abcd')({'message': 'ok', 'limit': 5})
'error'
That’s how ask
works and can be used.
RequiresContext
[-_EnvType, -_EnvType]
RequiresContextResult
(inner_value)[source]¶Bases: returns.primitives.container.BaseContainer
, typing.Generic
The RequiresContextResult
combinator.
See returns.context.requires_context.RequiresContext
for more docs.
This is just a handy wrapper around RequiresContext[env, Result[a, b]]
which represents a context-dependent pure operation
that might fail and return returns.result.Result
.
It has several important differences from the regular Result
classes.
It does not have Success
and Failure
subclasses.
Because, the computation is not yet performed.
And we cannot know the type in advance.
So, this is a thin wrapper, without any changes in logic.
Why do we need this wrapper? That’s just for better usability!
>>> from returns.context import RequiresContext
>>> from returns.result import Success, Result
>>> def function(arg: int) -> Result[int, str]:
... return Success(arg + 1)
>>> # Without wrapper:
>>> assert RequiresContext.from_value(Success(1)).map(
... lambda result: result.bind(function),
... )(...) == Success(2)
>>> # With wrapper:
>>> assert RequiresContextResult.from_success(1).bind_result(
... function,
... )(...) == Success(2)
This way RequiresContextResult
allows to simply work with:
raw values and pure functions
RequiresContext
values and pure functions returning it
Result
and functions returning it
Imporatant implementation detail:
due it is meaning, RequiresContextResult
cannot have Success
and Failure
subclasses.
We only have just one type. That’s by design.
Different converters are also not supported for this type.
Use converters inside the RequiresContext
context, not outside.
See also
https://dev.to/gcanti/getting-started-with-fp-ts-reader-1ie5 https://en.wikipedia.org/wiki/Lazy_evaluation https://bit.ly/2R8l4WK https://bit.ly/2RwP4fp
empty
= <object object>¶A convinient placeholder to call methods created by .from_value().
map
(function)[source]¶Composes successful container with a pure function.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> assert RequiresContextResult.from_success(1).map(
... lambda x: x + 1,
... )(...) == Success(2)
>>> assert RequiresContextResult.from_failure(1).map(
... lambda x: x + 1,
... )(...) == Failure(1)
RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind
(function)[source]¶Composes this container with a function returning the same type.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> def first(lg: bool) -> RequiresContextResult[float, int, int]:
... # `deps` has `float` type here:
... return RequiresContextResult(
... lambda deps: Success(deps) if lg else Failure(-deps),
... )
...
>>> def second(
... number: int,
... ) -> RequiresContextResult[float, str, int]:
... # `deps` has `float` type here:
... return RequiresContextResult(
... lambda deps: Success('>=' if number >= deps else '<'),
... )
...
>>> assert first(True).bind(second)(1) == Success('>=')
>>> assert first(False).bind(second)(2) == Failure(-2)
RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind_result
(function)[source]¶Binds Result
returning function to current container.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure, Result
>>> def function(number: int) -> Result[int, str]:
... if number > 0:
... return Success(number + 1)
... return Failure('<0')
...
>>> assert RequiresContextResult.from_success(1).bind_result(
... function,
... )(RequiresContextResult.empty) == Success(2)
>>> assert RequiresContextResult.from_success(0).bind_result(
... function,
... )(RequiresContextResult.empty) == Failure('<0')
>>> assert RequiresContextResult.from_failure(':(').bind_result(
... function,
... )(RequiresContextResult.empty) == Failure(':(')
RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind_context
(function)[source]¶Binds RequiresContext
returning function to current container.
>>> from returns.context import RequiresContext
>>> from returns.result import Success, Failure
>>> def function(arg: int) -> RequiresContext[str, int]:
... return RequiresContext(lambda deps: len(deps) + arg)
...
>>> assert function(2)('abc') == 5
>>> assert RequiresContextResult.from_success(2).bind_context(
... function,
... )('abc') == Success(5)
>>> assert RequiresContextResult.from_failure(2).bind_context(
... function,
... )('abc') == Failure(2)
RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]
fix
(function)[source]¶Composes failed container with a pure function.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success
>>> assert RequiresContextResult.from_success(1).fix(
... lambda x: x + 1,
... )(...) == Success(1)
>>> assert RequiresContextResult.from_failure(1).fix(
... lambda x: x + 1,
... )(...) == Success(2)
RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]
alt
(function)[source]¶Composes failed container with a pure function.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> assert RequiresContextResult.from_success(1).alt(
... lambda x: x + 1,
... )(...) == Success(1)
>>> assert RequiresContextResult.from_failure(1).alt(
... lambda x: x + 1,
... )(...) == Failure(2)
RequiresContextResult
[-_EnvType, +_ValueType, ~_NewErrorType]
rescue
(function)[source]¶Composes this container with a function returning the same type.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> def rescuable(arg: str) -> RequiresContextResult[str, str, str]:
... if len(arg) > 1:
... return RequiresContextResult(
... lambda deps: Success(deps + arg),
... )
... return RequiresContextResult(
... lambda deps: Failure(arg + deps),
... )
...
>>> assert RequiresContextResult.from_success('a').rescue(
... rescuable,
... )('c') == Success('a')
>>> assert RequiresContextResult.from_failure('a').rescue(
... rescuable,
... )('c') == Failure('ac')
>>> assert RequiresContextResult.from_failure('aa').rescue(
... rescuable,
... )('b') == Success('baa')
value_or
(default_value)[source]¶Returns a callable that either returns a success or default value.
>>> from returns.context import RequiresContextResult
>>> assert RequiresContextResult.from_success(1).value_or(2)(
... RequiresContextResult.empty,
... ) == 1
>>> assert RequiresContextResult.from_failure(1).value_or(2)(
... RequiresContextResult.empty,
... ) == 2
Callable
[[-_EnvType], Union
[+_ValueType, ~_FirstType]]
unwrap
()[source]¶Returns a callable that unwraps success value or raises exception.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> assert RequiresContextResult(
... lambda _: Success(1),
... ).unwrap()(RequiresContextResult.empty) == 1
>>> RequiresContextResult(
... lambda _: Failure(1),
... ).unwrap()(RequiresContextResult.empty)
Traceback (most recent call last):
...
returns.primitives.exceptions.UnwrapFailedError
Callable
[[-_EnvType], +_ValueType]
failure
()[source]¶Returns a callable that unwraps failure value or raises exception.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> assert RequiresContextResult(
... lambda _: Failure(1),
... ).failure()(RequiresContextResult.empty) == 1
>>> RequiresContextResult(
... lambda _: Success(1),
... ).failure()(RequiresContextResult.empty)
Traceback (most recent call last):
...
returns.primitives.exceptions.UnwrapFailedError
Callable
[[-_EnvType], +_ErrorType]
lift
(function)[source]¶Lifts function to be wrapped in a conatiner for better composition.
In other words, it modifies the function’s
signature from: a -> b
to:
RequiresContextResult[env, a, err]
-> RequiresContextResult[env, b, err]
Works similar to map()
,
but has inverse semantics.
This is how it should be used:
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success
>>> def function(arg: int) -> str:
... return str(arg) + '!'
...
>>> unit = RequiresContextResult.from_success(1)
>>> deps = RequiresContextResult.empty
>>> assert RequiresContextResult.lift(function)(
... unit,
... )(deps) == Success('1!')
See also
Callable
[[RequiresContextResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
lift_result
(function)[source]¶Lifts function from Result
for better composition.
In other words, it modifies the function’s
signature from: a -> Result[b, c]
to:
RequiresContextResult[env, a, c]
-> RequiresContextResult[env, b, c]
Similar to lift()
,
but works with other type.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure, Result
>>> def function(arg: int) -> Result[str, int]:
... if arg > 0:
... return Success(str(arg) + '!')
... return Failure(arg)
...
>>> deps = RequiresContextResult.empty
>>> assert RequiresContextResult.lift_result(function)(
... RequiresContextResult.from_success(1),
... )(deps) == Success('1!')
>>> assert RequiresContextResult.lift_result(function)(
... RequiresContextResult.from_success(0),
... )(deps) == Failure(0)
>>> assert RequiresContextResult.lift_result(function)(
... RequiresContextResult.from_failure('nope'),
... )(deps) == Failure('nope')
Callable
[[RequiresContextResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
lift_context
(function)[source]¶Lifts function from RequiresContext
for better composition.
In other words, it modifies the function’s
signature from: a -> RequiresContext[env, b]
to:
RequiresContextResult[env, a, c]
-> RequiresContextResult[env, b, c]
Similar to lift()
,
but works with other type.
>>> from returns.context import RequiresContext
>>> from returns.result import Success, Failure
>>> def function(arg: int) -> RequiresContext[str, int]:
... return RequiresContext(lambda deps: len(deps) + arg)
...
>>> assert RequiresContextResult.lift_context(function)(
... RequiresContextResult.from_success(2),
... )('abc') == Success(5)
>>> assert RequiresContextResult.lift_context(function)(
... RequiresContextResult.from_failure(0),
... )('abc') == Failure(0)
Callable
[[RequiresContextResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
from_result
(inner_value)[source]¶Creates new container with Result
as a unit value.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success, Failure
>>> deps = RequiresContextResult.empty
>>> assert RequiresContextResult.from_result(
... Success(1),
... )(deps) == Success(1)
>>> assert RequiresContextResult.from_result(
... Failure(1),
... )(deps) == Failure(1)
RequiresContextResult
[Any
, +_ValueType, +_ErrorType]
from_typecast
(container)[source]¶You might end up with RequiresContext[Result]
as a value.
This method is designed to turn it into RequiresContextResult
.
It will save all the typing information.
It is just more useful!
>>> from returns.context import RequiresContext
>>> from returns.result import Success, Failure
>>> assert RequiresContextResult.from_typecast(
... RequiresContext.from_value(Success(1)),
... )(RequiresContextResult.empty) == Success(1)
>>> assert RequiresContextResult.from_typecast(
... RequiresContext.from_value(Failure(1)),
... )(RequiresContextResult.empty) == Failure(1)
RequiresContextResult
[-_EnvType, ~_NewValueType, ~_NewErrorType]
from_successful_context
(inner_value)[source]¶Creates new container from RequiresContext
as a success unit.
>>> from returns.context import RequiresContext
>>> from returns.result import Success
>>> assert RequiresContextResult.from_successful_context(
... RequiresContext.from_value(1),
... )(...) == Success(1)
RequiresContextResult
[-_EnvType, ~_FirstType, Any
]
from_failed_context
(inner_value)[source]¶Creates new container from RequiresContext
as a failure unit.
>>> from returns.context import RequiresContext
>>> from returns.result import Failure
>>> assert RequiresContextResult.from_failed_context(
... RequiresContext.from_value(1),
... )(...) == Failure(1)
RequiresContextResult
[-_EnvType, Any
, ~_FirstType]
from_success
(inner_value)[source]¶Creates new container with Success(inner_value)
as a unit value.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Success
>>> assert RequiresContextResult.from_success(1)(...) == Success(1)
RequiresContextResult
[Any
, ~_FirstType, Any
]
from_failure
(inner_value)[source]¶Creates new container with Failure(inner_value)
as a unit value.
>>> from returns.context import RequiresContextResult
>>> from returns.result import Failure
>>> assert RequiresContextResult.from_failure(1)(...) == Failure(1)
RequiresContextResult
[Any
, Any
, ~_FirstType]
ContextResult
[source]¶Bases: returns.primitives.types.Immutable
, typing.Generic
Helpers that can be used to work with RequiresContextResult
container.
Related to returns.context.Context
, refer there for the docs.
ask
()[source]¶Is used to get the current dependencies inside the call stack.
Similar to returns.context.Context.ask()
,
but returns Result
instead of a regular value.
Please, refer to the docs there to know how to use it.
One important note that is worth doublicating here:
you might need to provide _EnvType
explicitly,
so mypy
will know about it statically.
>>> from returns.context import ContextResult
>>> from returns.result import Success
>>> assert ContextResult[int].ask().map(str)(1) == Success('1')
RequiresContextResult
[-_EnvType, -_EnvType, Any
]
RequiresContextResultE
¶Alias for a popular case when Result
has Exception
as error type.
alias of returns.context.requires_context_result.RequiresContextResult
ReaderResult
¶Alias to save you some typing. Uses original name from Haskell.
alias of returns.context.requires_context_result.RequiresContextResult
ReaderResultE
¶Alias to save you some typing. Has Exception
as error type.
alias of returns.context.requires_context_result.RequiresContextResult
RequiresContextIOResult
(inner_value)[source]¶Bases: returns.primitives.container.BaseContainer
, typing.Generic
The RequiresContextIOResult
combinator.
See returns.context.requires_context.RequiresContext
and returns.context.requires_context_result.RequiresContextResult
for more docs.
This is just a handy wrapper around
RequiresContext[env, IOResult[a, b]]
which represents a context-dependent impure operation that might fail.
It has several important differences from the regular Result
classes.
It does not have Success
and Failure
subclasses.
Because, the computation is not yet performed.
And we cannot know the type in advance.
So, this is a thin wrapper, without any changes in logic.
Why do we need this wrapper? That’s just for better usability!
>>> from returns.context import RequiresContext
>>> from returns.io import IOSuccess, IOResult
>>> def function(arg: int) -> IOResult[int, str]:
... return IOSuccess(arg + 1)
>>> # Without wrapper:
>>> assert RequiresContext.from_value(IOSuccess(1)).map(
... lambda ioresult: ioresult.bind(function),
... )(...) == IOSuccess(2)
>>> # With wrapper:
>>> assert RequiresContextIOResult.from_success(1).bind_ioresult(
... function,
... )(...) == IOSuccess(2)
This way RequiresContextIOResult
allows to simply work with:
raw values and pure functions
RequiresContext
values and pure functions returning it
RequiresContextResult
values and pure functions returning it
Result
and pure functions returning it
IOResult
and functions returning it
other RequiresContextIOResult
related functions and values
This is a complex type for complex tasks!
Imporatant implementation detail:
due it is meaning, RequiresContextIOResult
cannot have Success
and Failure
subclasses.
We only have just one type. That’s by design.
Different converters are also not supported for this type.
Use converters inside the RequiresContext
context, not outside.
See also
https://dev.to/gcanti/getting-started-with-fp-ts-reader-1ie5 https://en.wikipedia.org/wiki/Lazy_evaluation https://bit.ly/2R8l4WK https://bit.ly/2RwP4fp
empty
= <object object>¶A convinient placeholder to call methods created by .from_value().
map
(function)[source]¶Composes successful container with a pure function.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure
>>> assert RequiresContextIOResult.from_success(1).map(
... lambda x: x + 1,
... )(...) == IOSuccess(2)
>>> assert RequiresContextIOResult.from_failure(1).map(
... lambda x: x + 1,
... )(...) == IOFailure(1)
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind
(function)[source]¶Composes this container with a function returning the same type.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure
>>> def first(lg: bool) -> RequiresContextIOResult[float, int, int]:
... # `deps` has `float` type here:
... return RequiresContextIOResult(
... lambda deps: IOSuccess(deps) if lg else IOFailure(-deps),
... )
...
>>> def second(
... number: int,
... ) -> RequiresContextIOResult[float, str, int]:
... # `deps` has `float` type here:
... return RequiresContextIOResult(
... lambda deps: IOSuccess('>=' if number >= deps else '<'),
... )
...
>>> assert first(True).bind(second)(1) == IOSuccess('>=')
>>> assert first(False).bind(second)(2) == IOFailure(-2)
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind_result
(function)[source]¶Binds Result
returning function to the current container.
>>> from returns.context import RequiresContextIOResult
>>> from returns.result import Success, Failure, Result
>>> from returns.io import IOSuccess, IOFailure
>>> def function(number: int) -> Result[int, str]:
... if number > 0:
... return Success(number + 1)
... return Failure('<0')
...
>>> assert RequiresContextIOResult.from_success(1).bind_result(
... function,
... )(RequiresContextIOResult.empty) == IOSuccess(2)
>>> assert RequiresContextIOResult.from_success(0).bind_result(
... function,
... )(RequiresContextIOResult.empty) == IOFailure('<0')
>>> assert RequiresContextIOResult.from_failure(':(').bind_result(
... function,
... )(RequiresContextIOResult.empty) == IOFailure(':(')
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind_context
(function)[source]¶Binds RequiresContext
returning function to current container.
>>> from returns.context import RequiresContext
>>> from returns.io import IOSuccess, IOFailure
>>> def function(arg: int) -> RequiresContext[str, int]:
... return RequiresContext(lambda deps: len(deps) + arg)
...
>>> assert function(2)('abc') == 5
>>> assert RequiresContextIOResult.from_success(2).bind_context(
... function,
... )('abc') == IOSuccess(5)
>>> assert RequiresContextIOResult.from_failure(2).bind_context(
... function,
... )('abc') == IOFailure(2)
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind_context_result
(function)[source]¶Binds RequiresContextResult
returning function to the current one.
>>> from returns.context import RequiresContextResult
>>> from returns.io import IOSuccess, IOFailure
>>> from returns.result import Success, Failure
>>> def function(arg: int) -> RequiresContextResult[str, int, int]:
... if arg > 0:
... return RequiresContextResult(
... lambda deps: Success(len(deps) + arg),
... )
... return RequiresContextResult(
... lambda deps: Failure(len(deps) + arg),
... )
...
>>> assert function(2)('abc') == Success(5)
>>> assert function(-1)('abc') == Failure(2)
>>> assert RequiresContextIOResult.from_success(
... 2,
... ).bind_context_result(
... function,
... )('abc') == IOSuccess(5)
>>> assert RequiresContextIOResult.from_success(
... -1,
... ).bind_context_result(
... function,
... )('abc') == IOFailure(2)
>>> assert RequiresContextIOResult.from_failure(
... 2,
... ).bind_context_result(
... function,
... )('abc') == IOFailure(2)
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
bind_ioresult
(function)[source]¶Binds IOResult
returning function to the current container.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure
>>> def function(number: int) -> IOResult[int, str]:
... if number > 0:
... return IOSuccess(number + 1)
... return IOFailure('<0')
...
>>> assert RequiresContextIOResult.from_success(1).bind_ioresult(
... function,
... )(RequiresContextIOResult.empty) == IOSuccess(2)
>>> assert RequiresContextIOResult.from_success(0).bind_ioresult(
... function,
... )(RequiresContextIOResult.empty) == IOFailure('<0')
>>> assert RequiresContextIOResult.from_failure(':(').bind_ioresult(
... function,
... )(RequiresContextIOResult.empty) == IOFailure(':(')
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
fix
(function)[source]¶Composes failed container with a pure function.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess
>>> assert RequiresContextIOResult.from_success(1).fix(
... lambda x: x + 1,
... )(...) == IOSuccess(1)
>>> assert RequiresContextIOResult.from_failure(1).fix(
... lambda x: x + 1,
... )(...) == IOSuccess(2)
RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]
alt
(function)[source]¶Composes failed container with a pure function.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure
>>> assert RequiresContextIOResult.from_success(1).alt(
... lambda x: x + 1,
... )(...) == IOSuccess(1)
>>> assert RequiresContextIOResult.from_failure(1).alt(
... lambda x: x + 1,
... )(...) == IOFailure(2)
RequiresContextIOResult
[-_EnvType, +_ValueType, ~_NewErrorType]
rescue
(function)[source]¶Composes this container with a function returning the same type.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure
>>> def rescuable(
... arg: str,
... ) -> RequiresContextIOResult[str, str, str]:
... if len(arg) > 1:
... return RequiresContextIOResult(
... lambda deps: IOSuccess(deps + arg),
... )
... return RequiresContextIOResult(
... lambda deps: IOFailure(arg + deps),
... )
...
>>> assert RequiresContextIOResult.from_success('a').rescue(
... rescuable,
... )('c') == IOSuccess('a')
>>> assert RequiresContextIOResult.from_failure('a').rescue(
... rescuable,
... )('c') == IOFailure('ac')
>>> assert RequiresContextIOResult.from_failure('aa').rescue(
... rescuable,
... )('b') == IOSuccess('baa')
value_or
(default_value)[source]¶Returns a callable that either returns a success or default value.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IO
>>> assert RequiresContextIOResult.from_success(1).value_or(2)(
... RequiresContextIOResult.empty,
... ) == IO(1)
>>> assert RequiresContextIOResult.from_failure(1).value_or(2)(
... RequiresContextIOResult.empty,
... ) == IO(2)
Callable
[[-_EnvType], IO
[Union
[+_ValueType, ~_FirstType]]]
unwrap
()[source]¶Returns a callable that unwraps success value or raises exception.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IO
>>> assert RequiresContextIOResult.from_success(1).unwrap()(
... RequiresContextIOResult.empty,
... ) == IO(1)
>>> RequiresContextIOResult.from_failure(1).unwrap()(
... RequiresContextIOResult.empty,
... )
Traceback (most recent call last):
...
returns.primitives.exceptions.UnwrapFailedError
Callable
[[-_EnvType], IO
[+_ValueType]]
failure
()[source]¶Returns a callable that unwraps failure value or raises exception.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IO
>>> assert RequiresContextIOResult.from_failure(1).failure()(
... RequiresContextIOResult.empty,
... ) == IO(1)
>>> RequiresContextIOResult.from_success(1).failure()(
... RequiresContextIOResult.empty,
... )
Traceback (most recent call last):
...
returns.primitives.exceptions.UnwrapFailedError
Callable
[[-_EnvType], IO
[+_ErrorType]]
lift
(function)[source]¶Lifts function to be wrapped in a conatiner for better composition.
In other words, it modifies the function’s
signature from: a -> b
to:
RequiresContextIOResult[env, a, err]
-> RequiresContextIOResult[env, b, err]
Works similar to map()
,
but has inverse semantics.
This is how it should be used:
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess
>>> def function(arg: int) -> str:
... return str(arg) + '!'
...
>>> unit = RequiresContextIOResult.from_success(1)
>>> deps = RequiresContextIOResult.empty
>>> assert RequiresContextIOResult.lift(function)(
... unit,
... )(deps) == IOSuccess('1!')
See also
Callable
[[RequiresContextIOResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
lift_result
(function)[source]¶Lifts function from Result
for better composition.
In other words, it modifies the function’s
signature from: a -> Result[b, c]
to:
RequiresContextIOResult[env, a, c]
-> RequiresContextIOResult[env, b, c]
Similar to lift()
,
but works with other type.
>>> from returns.context import RequiresContextIOResult
>>> from returns.result import Success, Failure, Result
>>> from returns.io import IOSuccess, IOFailure
>>> def function(arg: int) -> Result[str, int]:
... if arg > 0:
... return Success(str(arg) + '!')
... return Failure(arg)
...
>>> deps = RequiresContextIOResult.empty
>>> assert RequiresContextIOResult.lift_result(function)(
... RequiresContextIOResult.from_success(1),
... )(deps) == IOSuccess('1!')
>>> assert RequiresContextIOResult.lift_result(function)(
... RequiresContextIOResult.from_success(0),
... )(deps) == IOFailure(0)
>>> assert RequiresContextIOResult.lift_result(function)(
... RequiresContextIOResult.from_failure('nope'),
... )(deps) == IOFailure('nope')
Callable
[[RequiresContextIOResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
lift_ioresult
(function)[source]¶Lifts function from IOResult
for better composition.
In other words, it modifies the function’s
signature from: a -> IOResult[b, c]
to:
RequiresContextIOResult[env, a, c]
-> RequiresContextIOResult[env, b, c]
Similar to lift()
,
but works with other type.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure, IOResult
>>> def function(arg: int) -> IOResult[str, int]:
... if arg > 0:
... return IOSuccess(str(arg) + '!')
... return IOFailure(arg)
...
>>> deps = RequiresContextIOResult.empty
>>> assert RequiresContextIOResult.lift_ioresult(function)(
... RequiresContextIOResult.from_success(1),
... )(deps) == IOSuccess('1!')
>>> assert RequiresContextIOResult.lift_ioresult(function)(
... RequiresContextIOResult.from_success(0),
... )(deps) == IOFailure(0)
>>> assert RequiresContextIOResult.lift_ioresult(function)(
... RequiresContextIOResult.from_failure('nope'),
... )(deps) == IOFailure('nope')
Callable
[[RequiresContextIOResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
lift_context
(function)[source]¶Lifts function from RequiresContext
for better composition.
In other words, it modifies the function’s
signature from: a -> RequiresContext[env, b]
to:
RequiresContextIOResult[env, a, c]
-> RequiresContextIOResult[env, b, c]
Similar to lift()
,
but works with other type.
>>> from returns.context import RequiresContext
>>> from returns.io import IOSuccess, IOFailure
>>> def function(arg: int) -> RequiresContext[str, int]:
... return RequiresContext(lambda deps: len(deps) + arg)
...
>>> assert RequiresContextIOResult.lift_context(function)(
... RequiresContextIOResult.from_success(2),
... )('abc') == IOSuccess(5)
>>> assert RequiresContextIOResult.lift_context(function)(
... RequiresContextIOResult.from_failure(0),
... )('abc') == IOFailure(0)
Callable
[[RequiresContextIOResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
lift_context_result
(function)[source]¶Lifts function from RequiresContextResult
for better composition.
In other words, it modifies the function’s
signature from: a -> RequiresContextResult[env, b, c]
to:
RequiresContextIOResult[env, a, c]
-> RequiresContextIOResult[env, b, c]
Similar to lift()
,
but works with other type.
>>> from returns.context import RequiresContextResult
>>> from returns.io import IOSuccess, IOFailure
>>> from returns.result import Success
>>> def function(arg: int) -> RequiresContextResult[str, int, str]:
... return RequiresContextResult(
... lambda deps: Success(len(deps) + arg),
... )
...
>>> assert RequiresContextIOResult.lift_context_result(function)(
... RequiresContextIOResult.from_success(2),
... )('abc') == IOSuccess(5)
>>> assert RequiresContextIOResult.lift_context_result(function)(
... RequiresContextIOResult.from_failure(0),
... )('abc') == IOFailure(0)
Callable
[[RequiresContextIOResult
[-_EnvType, +_ValueType, +_ErrorType]], RequiresContextIOResult
[-_EnvType, ~_NewValueType, +_ErrorType]]
from_result
(inner_value)[source]¶Creates new container with Result
as a unit value.
>>> from returns.context import RequiresContextIOResult
>>> from returns.result import Success, Failure
>>> from returns.io import IOSuccess, IOFailure
>>> deps = RequiresContextIOResult.empty
>>> assert RequiresContextIOResult.from_result(
... Success(1),
... )(deps) == IOSuccess(1)
>>> assert RequiresContextIOResult.from_result(
... Failure(1),
... )(deps) == IOFailure(1)
RequiresContextIOResult
[Any
, +_ValueType, +_ErrorType]
from_ioresult
(inner_value)[source]¶Creates new container with Result
as a unit value.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess, IOFailure
>>> deps = RequiresContextIOResult.empty
>>> assert RequiresContextIOResult.from_ioresult(
... IOSuccess(1),
... )(deps) == IOSuccess(1)
>>> assert RequiresContextIOResult.from_ioresult(
... IOFailure(1),
... )(deps) == IOFailure(1)
RequiresContextIOResult
[Any
, +_ValueType, +_ErrorType]
from_typecast
(container)[source]¶You might end up with RequiresContext[IOResult]
as a value.
This method is designed to turn it into RequiresContextIOResult
.
It will save all the typing information.
It is just more useful!
>>> from returns.context import RequiresContext
>>> from returns.io import IOSuccess, IOFailure
>>> assert RequiresContextIOResult.from_typecast(
... RequiresContext.from_value(IOSuccess(1)),
... )(RequiresContextIOResult.empty) == IOSuccess(1)
>>> assert RequiresContextIOResult.from_typecast(
... RequiresContext.from_value(IOFailure(1)),
... )(RequiresContextIOResult.empty) == IOFailure(1)
RequiresContextIOResult
[-_EnvType, ~_NewValueType, ~_NewErrorType]
from_successful_context
(inner_value)[source]¶Creates new container from RequiresContext
as a success unit.
>>> from returns.context import RequiresContext
>>> from returns.io import IOSuccess
>>> assert RequiresContextIOResult.from_successful_context(
... RequiresContext.from_value(1),
... )(...) == IOSuccess(1)
RequiresContextIOResult
[-_EnvType, ~_FirstType, Any
]
from_failed_context
(inner_value)[source]¶Creates new container from RequiresContext
as a failure unit.
>>> from returns.context import RequiresContext
>>> from returns.io import IOFailure
>>> assert RequiresContextIOResult.from_failed_context(
... RequiresContext.from_value(1),
... )(...) == IOFailure(1)
RequiresContextIOResult
[-_EnvType, Any
, ~_FirstType]
from_result_context
(inner_value)[source]¶Creates new container from RequiresContextResult
as a unit value.
>>> from returns.context import RequiresContextResult
>>> from returns.io import IOSuccess, IOFailure
>>> assert RequiresContextIOResult.from_result_context(
... RequiresContextResult.from_success(1),
... )(...) == IOSuccess(1)
>>> assert RequiresContextIOResult.from_result_context(
... RequiresContextResult.from_failure(1),
... )(...) == IOFailure(1)
RequiresContextIOResult
[-_EnvType, +_ValueType, +_ErrorType]
from_success
(inner_value)[source]¶Creates new container with IOSuccess(inner_value)
as a unit value.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOSuccess
>>> assert RequiresContextIOResult.from_success(1)(
... RequiresContextIOResult.empty,
... ) == IOSuccess(1)
RequiresContextIOResult
[Any
, ~_FirstType, Any
]
from_failure
(inner_value)[source]¶Creates new container with IOFailure(inner_value)
as a unit value.
>>> from returns.context import RequiresContextIOResult
>>> from returns.io import IOFailure
>>> assert RequiresContextIOResult.from_failure(1)(
... RequiresContextIOResult.empty,
... ) == IOFailure(1)
RequiresContextIOResult
[Any
, Any
, ~_FirstType]
ContextIOResult
[source]¶Bases: returns.primitives.types.Immutable
, typing.Generic
Helpers that can be used to work with RequiresContextIOResult
container.
Related to returns.context.requires_context.Context
and returns.context.requires_context_result.ContextResult
,
refer there for the docs.
ask
()[source]¶Is used to get the current dependencies inside the call stack.
Similar to returns.context.requires_context.Context.ask()
,
but returns IOResult
instead of a regular value.
Please, refer to the docs there to know how to use it.
One important note that is worth doublicating here:
you might need to provide _EnvType
explicitly,
so mypy
will know about it statically.
>>> from returns.context import ContextIOResult
>>> from returns.io import IOSuccess
>>> assert ContextIOResult[int].ask().map(str)(1) == IOSuccess('1')
RequiresContextIOResult
[-_EnvType, -_EnvType, Any
]
RequiresContextIOResultE
¶Alias for a popular case when Result
has Exception
as error type.
alias of returns.context.requires_context_io_result.RequiresContextIOResult
ReaderIOResult
¶Alias to save you some typing. Uses original name from Haskell.
alias of returns.context.requires_context_io_result.RequiresContextIOResult
ReaderIOResultE
¶Alias to save you some typing. Uses Exception
as error type.
alias of returns.context.requires_context_io_result.RequiresContextIOResult