Beispiel #1
0
    def right_identity(
        container: 'ContainerN[_FirstType, _SecondType, _ThirdType]',
    ) -> None:
        """
        Right identity.

        The second law states that if we have a container value
        and we use ``bind`` to feed it to ``.from_value``,
        the result is our original container value.
        """
        assert_equal(
            container,
            container.bind(lambda inner: container.from_value(inner), ),
        )
Beispiel #2
0
    def composition_law(
        container: 'ApplicativeN[_FirstType, _SecondType, _ThirdType]',
        first: Callable[[_FirstType], _NewType1],
        second: Callable[[_NewType1], _NewType2],
    ) -> None:
        """
        Composition law.

        Apply two functions twice is the same
        as applying their composition once.
        """
        assert_equal(
            container.apply(container.from_value(compose(first, second))),
            container.apply(container.from_value(first), ).apply(
                container.from_value(second), ),
        )
Beispiel #3
0
    def bind_short_circuit_law(
        raw_value: _SecondType,
        container: 'DiverseFailableN[_FirstType, _SecondType, _ThirdType]',
        function: Callable[[_FirstType],
                           KindN['DiverseFailableN', _NewFirstType,
                                 _SecondType, _ThirdType], ],
    ) -> None:
        """
        Ensures that you cannot bind a failure.

        See: https://wiki.haskell.org/Typeclassopedia#MonadFail
        """
        assert_equal(
            container.from_failure(raw_value),
            container.from_failure(raw_value).bind(function),
        )
Beispiel #4
0
    def left_identity(
        raw_value: _FirstType,
        container: 'ContainerN[_FirstType, _SecondType, _ThirdType]',
        function: Callable[[_FirstType], KindN['ContainerN', _NewType1,
                                               _SecondType, _ThirdType], ],
    ) -> None:
        """
        Left identity.

        The first law states that if we take a value, put it in a default
        context with return and then feed it to a function by using ``bind``,
        it's the same as just taking the value and applying the function to it.
        """
        assert_equal(
            container.from_value(raw_value).bind(function),
            function(raw_value),
        )
Beispiel #5
0
    def homomorphism_law(
        raw_value: _FirstType,
        container: 'ApplicativeN[_FirstType, _SecondType, _ThirdType]',
        function: Callable[[_FirstType], _NewType1],
    ) -> None:
        """
        Homomorphism law.

        The homomorphism law says that
        applying a wrapped function to a wrapped value is the same
        as applying the function to the value in the normal way
        and then using ``.from_value`` on the result.
        """
        assert_equal(
            container.from_value(function(raw_value)),
            container.from_value(raw_value).apply(
                container.from_value(function), ),
        )
Beispiel #6
0
    def associativity(
        container: 'ContainerN[_FirstType, _SecondType, _ThirdType]',
        first: Callable[[_FirstType], KindN['ContainerN', _NewType1,
                                            _SecondType, _ThirdType], ],
        second: Callable[[_NewType1], KindN['ContainerN', _NewType2,
                                            _SecondType, _ThirdType], ],
    ) -> None:
        """
        Associativity law.

        The final monad law says that when
        we have a chain of container functions applications with ``bind``,
        it shouldn’t matter how they’re nested.
        """
        assert_equal(
            container.bind(first).bind(second),
            container.bind(lambda inner: first(inner).bind(second)),
        )
Beispiel #7
0
    def interchange_law(
        raw_value: _FirstType,
        container: 'ApplicativeN[_FirstType, _SecondType, _ThirdType]',
        function: Callable[[_FirstType], _NewType1],
    ) -> None:
        """
        Interchange law.

        Basically we check that we can start our composition
        with both ``raw_value`` and ``function``.

        Great explanation: https://stackoverflow.com/q/27285918/4842742
        """
        assert_equal(
            container.from_value(raw_value).apply(
                container.from_value(function), ),
            container.from_value(function).apply(
                container.from_value(lambda inner: inner(raw_value)), ),
        )
Beispiel #8
0
 def identity_law(
     mappable: 'MappableN[_FirstType, _SecondType, _ThirdType]', ) -> None:
     """Mapping identity over a value must return the value unchanged."""
     assert_equal(mappable.map(identity), mappable)
Beispiel #9
0
def test_assert_equal(container, anyio_backend_name: str):
    """Ensure that containers can be equal."""
    assert_equal(container, container, backend=anyio_backend_name)