1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
from __future__ import annotations
from abc import abstractmethod
from collections.abc import Callable, Sequence
from typing import TYPE_CHECKING, ClassVar, TypeVar, final
from returns.interfaces.specific import reader, result
from returns.primitives.hkt import KindN
from returns.primitives.laws import (
Law,
Law2,
Lawful,
LawSpecDef,
law_definition,
)
if TYPE_CHECKING:
from returns.context import Reader, ReaderResult # noqa: WPS433
from returns.result import Result # noqa: F401, WPS433
_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_ThirdType = TypeVar('_ThirdType')
_UpdatedType = TypeVar('_UpdatedType')
_ValueType = TypeVar('_ValueType')
_ErrorType = TypeVar('_ErrorType')
_EnvType = TypeVar('_EnvType')
_ReaderResultLikeType = TypeVar(
'_ReaderResultLikeType',
bound='ReaderResultLikeN',
)
class ReaderResultLikeN(
reader.ReaderLike3[_FirstType, _SecondType, _ThirdType],
result.ResultLikeN[_FirstType, _SecondType, _ThirdType],
):
"""
Base interface for all types that do look like ``ReaderResult`` instance.
Cannot be called.
"""
__slots__ = ()
@abstractmethod
def bind_context_result(
self: _ReaderResultLikeType,
function: Callable[
[_FirstType],
ReaderResult[_UpdatedType, _SecondType, _ThirdType],
],
) -> KindN[_ReaderResultLikeType, _UpdatedType, _SecondType, _ThirdType]:
"""Binds a ``ReaderResult`` returning function over a container."""
@classmethod
@abstractmethod
def from_failed_context(
cls: type[_ReaderResultLikeType],
inner_value: Reader[_ErrorType, _EnvType],
) -> KindN[_ReaderResultLikeType, _FirstType, _ErrorType, _EnvType]:
"""Unit method to create new containers from failed ``Reader``."""
@classmethod
@abstractmethod
def from_result_context(
cls: type[_ReaderResultLikeType],
inner_value: ReaderResult[_ValueType, _ErrorType, _EnvType],
) -> KindN[_ReaderResultLikeType, _ValueType, _ErrorType, _EnvType]:
"""Unit method to create new containers from ``ReaderResult``."""
#: Type alias for kinds with three type arguments.
ReaderResultLike3 = ReaderResultLikeN[_FirstType, _SecondType, _ThirdType]
@final
class _LawSpec(LawSpecDef):
"""
Concrete laws for ``ReaderResulBasedN``.
See: https://github.com/haskell/mtl/pull/61/files
"""
__slots__ = ()
@law_definition
def purity_law(
container: ReaderResultBasedN[_FirstType, _SecondType, _ThirdType],
env: _ThirdType,
) -> None:
"""Calling a ``Reader`` twice has the same result with the same env."""
assert container(env) == container(env)
@law_definition
def asking_law(
container: ReaderResultBasedN[_FirstType, _SecondType, _ThirdType],
env: _ThirdType,
) -> None:
"""Asking for an env, always returns the env."""
assert container.ask().__call__( # noqa: PLC2801
env,
) == container.from_value(env).__call__(env) # noqa: PLC2801
class ReaderResultBasedN(
ReaderResultLikeN[_FirstType, _SecondType, _ThirdType],
reader.CallableReader3[
_FirstType,
_SecondType,
_ThirdType,
# Calls:
'Result[_FirstType, _SecondType]',
_ThirdType,
],
Lawful['ReaderResultBasedN[_FirstType, _SecondType, _ThirdType]'],
):
"""
This interface is very specific to our ``ReaderResult`` type.
The only thing that differs from ``ReaderResultLikeN`` is that we know
the specific types for its ``__call__`` method.
In this case the return type of ``__call__`` is ``Result``.
"""
__slots__ = ()
_laws: ClassVar[Sequence[Law]] = (
Law2(_LawSpec.purity_law),
Law2(_LawSpec.asking_law),
)
#: Type alias for kinds with three type arguments.
ReaderResultBased3 = ReaderResultBasedN[_FirstType, _SecondType, _ThirdType]
|