Source code for haskpy.typeclasses.profunctor

from hypothesis import given
from hypothesis import strategies as st

from .contravariant import Contravariant
from .functor import Functor
from haskpy.utils import (
    identity,
    assert_output,
    class_function,
    abstract_class_function,
)
from haskpy import testing


[docs]class Profunctor(Functor, Contravariant): """Profunctor Minimal complete definition: ``dimap | (contramap & map)``. Instead of using ``lmap`` and ``rmap`` as in Haskell, let's use the already introduced ``contramap`` and ``map``. """
[docs] def dimap(self, f, g): """p b c -> (a -> b) -> (c -> d) -> p a d""" return self.contramap(f).map(g)
[docs] def contramap(self, f): """(a -> b) -> p b c -> p a c""" return self.dimap(f, identity)
[docs] def map(self, g): """(b -> c) -> p a b -> p a c""" return self.dimap(identity, g)
# # Sampling methods for property tests # @abstract_class_function def sample_profunctor_type(cls, a, b): pass # # Test typeclass laws # @class_function @assert_output def assert_profunctor_identity(cls, x): return ( x, x.dimap(identity, identity), ) @class_function @given(st.data()) def test_profunctor_identity(cls, data): # Draw types a = data.draw(testing.sample_eq_type()) b = data.draw(testing.sample_type()) fab = data.draw(cls.sample_profunctor_type(a, b)) # Draw values x = data.draw(fab) cls.assert_profunctor_identity(x, data=data) return # # Test laws based on default implementations # @class_function @assert_output def assert_profunctor_dimap(cls, x, f, g): from haskpy.functions import dimap return ( Profunctor.dimap(x, f, g), x.dimap(f, g), dimap(f, g, x), ) @class_function @given(st.data()) def test_profunctor_dimap(cls, data): # Draw types b = data.draw(testing.sample_eq_type()) c = data.draw(testing.sample_eq_type()) d = data.draw(testing.sample_type()) fbc = data.draw(cls.sample_profunctor_type(b, c)) # Draw values x = data.draw(fbc) f = data.draw(testing.sample_function(b)) g = data.draw(testing.sample_function(d)) cls.assert_profunctor_dimap(x, f, g, data=data) return @class_function @assert_output def assert_profunctor_map(cls, x, f): return ( Profunctor.map(x, f), x.map(f), ) @class_function @given(st.data()) def test_profunctor_map(cls, data): # Draw types b = data.draw(testing.sample_eq_type()) c = data.draw(testing.sample_eq_type()) d = data.draw(testing.sample_type()) fbc = data.draw(cls.sample_profunctor_type(b, c)) # Draw values x = data.draw(fbc) g = data.draw(testing.sample_function(d)) cls.assert_profunctor_map(x, g, data=data) return @class_function @assert_output def assert_profunctor_contramap(cls, x, f): return ( Profunctor.contramap(x, f), x.contramap(f), ) @class_function @given(st.data()) def test_profunctor_contramap(cls, data): # Draw types b = data.draw(testing.sample_eq_type()) d = data.draw(testing.sample_type()) fbd = data.draw(cls.sample_profunctor_type(b, d)) # Draw values x = data.draw(fbd) f = data.draw(testing.sample_function(b)) cls.assert_profunctor_contramap(x, f, data=data) return
# Profunctor-related functions are defined in function module because of # circular dependency.