Source code for haskpy.typeclasses._cartesian

from hypothesis import given
from hypothesis import strategies as st

from haskpy.internal import class_function
from haskpy.testing import assert_output
from haskpy import testing

# Use the "hidden" module in order to avoid circular imports
from ._profunctor import Profunctor


[docs]class Cartesian(Profunctor): """Cartesian profunctor Perhaps better known as Strong in Haskell: https://hackage.haskell.org/package/profunctors-5.2/docs/Data-Profunctor-Strong.html I decided to use name Cartesian because that was used in the profunctor optics paper. Minimal complete definition: ``first | second``. """
[docs] def first(self): """p a b -> p (a, c) (b, c)""" return self.second().dimap(_flip_tuple, _flip_tuple)
[docs] def second(self): """p a b -> p (c, a) (c, a)""" return self.first().dimap(_flip_tuple, _flip_tuple)
# # Test Cartesian laws # @class_function @assert_output def assert_cartesian_identity(cls, h): lunit = lambda a_1: a_1[0] runit = lambda a: (a, ()) return ( h.dimap(lunit, runit), h.first(), ) @class_function @given(st.data()) def test_cartesian_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 h = data.draw(fab) cls.assert_cartesian_identity( h, data=data, input_strategy=st.tuples(st.integers(), st.just(())), ) return @class_function @assert_output def assert_cartesian_associativity(cls, h): lassoc = lambda a_bc: ((a_bc[0], a_bc[1][0]), a_bc[1][1]) rassoc = lambda ab_c: (ab_c[0][0], (ab_c[0][1], ab_c[1])) return ( h.first().first().dimap(lassoc, rassoc), h.first(), ) @class_function @given(st.data()) def test_cartesian_associativity(cls, data): # Draw types a = st.tuples( data.draw(testing.sample_eq_type()), st.tuples( st.just("foo"), st.just("bar"), ) ) b = data.draw(testing.sample_type()) fab = data.draw(cls.sample_profunctor_type(a, b)) # Draw values h = data.draw(fab) cls.assert_cartesian_associativity(h, data=data, input_strategy=a) return # # Test laws based on default implementations # @class_function @assert_output def assert_cartesian_first(cls, x): return ( Cartesian.first(x), x.first(), ) @class_function @given(st.data()) def test_cartesian_first(cls, data): # Draw types a1 = data.draw(testing.sample_eq_type()) a2 = data.draw(testing.sample_eq_type()) a = st.tuples(a1, a2) b = data.draw(testing.sample_type()) fab = data.draw(cls.sample_profunctor_type(a, b)) # Draw values x = data.draw(fab) cls.assert_cartesian_first( x, data=data, input_strategy=a, ) return @class_function @assert_output def assert_cartesian_second(cls, x): return ( Cartesian.second(x), x.second(), ) @class_function @given(st.data()) def test_cartesian_second(cls, data): # Draw types a1 = data.draw(testing.sample_eq_type()) a2 = data.draw(testing.sample_eq_type()) a = st.tuples(a1, a2) b = data.draw(testing.sample_type()) fab = data.draw(cls.sample_profunctor_type(a, b)) # Draw values x = data.draw(fab) cls.assert_cartesian_second( x, data=data, input_strategy=a, ) return
def _flip_tuple(ab): return (ab[1], ab[0])