from abc import abstractmethod
from typing import (
Callable,
ClassVar,
Generic,
NoReturn,
Sequence,
TypeVar,
final,
)
from returns.functions import compose, identity
from returns.primitives.asserts import assert_equal
from returns.primitives.hkt import KindN
from returns.primitives.laws import (
Law,
Law1,
Law3,
Lawful,
LawSpecDef,
law_definition,
)
_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_ThirdType = TypeVar('_ThirdType')
_UpdatedType = TypeVar('_UpdatedType')
_AltableType = TypeVar('_AltableType', bound='AltableN')
# Used in laws:
_NewType1 = TypeVar('_NewType1')
_NewType2 = TypeVar('_NewType2')
[docs]@final
class _LawSpec(LawSpecDef):
"""
Mappable or functor laws.
https://en.wikibooks.org/wiki/Haskell/The_Functor_class#The_functor_laws
"""
__slots__ = ()
[docs] @law_definition
def identity_law(
altable: 'AltableN[_FirstType, _SecondType, _ThirdType]',
) -> None:
"""Mapping identity over a value must return the value unchanged."""
assert_equal(altable.alt(identity), altable)
[docs] @law_definition
def associative_law(
altable: 'AltableN[_FirstType, _SecondType, _ThirdType]',
first: Callable[[_SecondType], _NewType1],
second: Callable[[_NewType1], _NewType2],
) -> None:
"""Mapping twice or mapping a composition is the same thing."""
assert_equal(
altable.alt(first).alt(second),
altable.alt(compose(first, second)),
)
[docs]class AltableN(
Generic[_FirstType, _SecondType, _ThirdType],
Lawful['AltableN[_FirstType, _SecondType, _ThirdType]'],
):
"""Modifies the second type argument with a pure function."""
__slots__ = ()
_laws: ClassVar[Sequence[Law]] = (
Law1(_LawSpec.identity_law),
Law3(_LawSpec.associative_law),
)
[docs] @abstractmethod
def alt(
self: _AltableType,
function: Callable[[_SecondType], _UpdatedType],
) -> KindN[_AltableType, _FirstType, _UpdatedType, _ThirdType]:
"""Allows to run a pure function over a container."""
#: Type alias for kinds with two type arguments.
Altable2 = AltableN[_FirstType, _SecondType, NoReturn]
#: Type alias for kinds with three type arguments.
Altable3 = AltableN[_FirstType, _SecondType, _ThirdType]