To create a custom container in returns, follow these steps:
- Choose Interfaces: Decide which capabilities your container needs. You can subtype specific interfaces like
MappableN, BindableN, AltableN, LashableN, or Equable. You can also use pre-defined aliases like BiMappableN or SwappableN to combine multiple interfaces. - Implement BaseContainer: It is highly recommended to inherit from
returns.primitives.container.BaseContainer to gain features like immutability, cloning, serialization, and comparison. - Implement Methods: You must implement all abstract methods required by the interfaces you subtype (e.g.,
map, bind, lash, alt, swap) to satisfy mypy type checking. - Define Custom Interfaces: If existing interfaces don't cover your needs, define a new interface (e.g., using
typing.Protocol) and add it as a supertype. - Verify Laws: Use
hypothesis to check that your container adheres to functional programming laws. You can define custom laws using a LawSpec and verify them with check_all_laws. - Write Type-Tests: Use
mypy snapshots (e.g., with pytest-mypy-plugins) to ensure your container's type signatures behave correctly under both valid and invalid usage.
from typing import Callable, TypeVar, Tuple, final
from returns.interfaces import bindable, equable, lashable, swappable
from returns.primitives.container import BaseContainer
from returns.primitives.hkt import SupportsKind2
_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_NewFirstType = TypeVar('_NewFirstType')
_NewSecondType = TypeVar('_NewSecondType')
@final
class Pair(
BaseContainer,
SupportsKind2['Pair', _FirstType, _SecondType],
bindable.Bindable2[_FirstType, _SecondType],
swappable.Swappable2[_FirstType, _SecondType],
lashable.Lashable2[_FirstType, _SecondType],
equable.Equable,
):
def __init__(
self, inner_value: Tuple[_FirstType, _SecondType],
) -> None:
super().__init__(inner_value)