Source code for haskpy.typeclasses.contravariant
from hypothesis import given
from hypothesis import strategies as st
from .typeclass import Type
from haskpy.utils import (
identity,
assert_output,
class_function,
abstract_class_function,
)
from haskpy import testing
[docs]class Contravariant(Type):
"""Contravariant functor
Minimal complete definition:
- ``contramap`` method
"""
[docs] def contramap(self, f):
"""f b -> (a -> b) -> f a"""
raise NotImplementedError()
[docs] def contrareplace(self, x):
"""f b -> b -> f a"""
return self.contramap(lambda _: x)
#
# Sampling methods for property tests
#
@abstract_class_function
def sample_contravariant_type(cls, a):
pass
#
# Test typeclass laws
#
@class_function
@assert_output
def assert_contravariant_identity(cls, v):
return(
v,
v.contramap(identity),
)
@class_function
@given(st.data())
def test_contravariant_identity(cls, data):
# Draw types
a = data.draw(testing.sample_type())
ta = data.draw(cls.sample_contravariant_type(a))
# Draw values
v = data.draw(ta)
cls.assert_contravariant_identity(v, data=data)
return
@class_function
@assert_output
def assert_contravariant_composition(cls, v, f, g):
return (
v.contramap(f).contramap(g),
v.contramap(lambda x: f(g(x))),
)
@class_function
@given(st.data())
def test_contravariant_composition(cls, data):
# Draw types
a = data.draw(testing.sample_type())
b = data.draw(testing.sample_eq_type())
c = data.draw(testing.sample_eq_type())
ta = data.draw(cls.sample_contravariant_type(a))
# Draw values
v = data.draw(ta)
f = data.draw(testing.sample_function(b))
g = data.draw(testing.sample_function(c))
cls.assert_contravariant_composition(v, f, g, data=data)
return
#
# Test laws based on default implementations
#
@class_function
@assert_output
def assert_contravariant_contramap(cls, v, f):
from haskpy.functions import contramap
return (
v.contramap(f),
contramap(f, v),
)
@class_function
@given(st.data())
def test_contravariant_contramap(cls, data):
# Draw types
a = data.draw(testing.sample_type())
b = data.draw(testing.sample_eq_type())
ta = data.draw(cls.sample_contravariant_type(a))
# Draw values
v = data.draw(ta)
f = data.draw(testing.sample_function(b))
cls.assert_contravariant_contramap(v, f, data=data)
return
@class_function
@assert_output
def assert_contravariant_contrareplace(cls, v, x):
from haskpy.functions import contrareplace
return (
Contravariant.contrareplace(v, x),
contrareplace(x, v),
v.contrareplace(x),
)
@class_function
@given(st.data())
def test_contravariant_contrareplace(cls, data):
# Draw types
a = data.draw(testing.sample_type())
b = data.draw(testing.sample_eq_type())
ta = data.draw(cls.sample_contravariant_type(a))
# Draw values
v = data.draw(ta)
x = data.draw(b)
cls.assert_contravariant_contrareplace(v, x, data=data)
return
# Contravariant-related functions are defined in function module because of
# circular dependency.