我一直试图通过将它们翻译成Python来理解Haskell中的一些抽象概念,但我似乎无法弄清楚如何编写一个满足定义逆变函子的公理的类。
我认为以下课程在非可迭代的基础上捕捉基本仿函数的概念。类型。
from typing import Any, Iterable
from types import FunctionType as Function
from abc import abstractmethod
class _FunctorBase:
value: Any = None
def __call__(self, value: Any) -> '_FunctorBase':
""" Make the functor type callable """
self.value = value
return self
def __str__(self) -> str:
return f'{self.__class__.__name__}({self.value})'
def __repr__(self) -> str:
return self.__str__()
def __eq__(self, other: '_FunctorBase') -> bool:
return self.value == other.value
def __ne__(self, other: '_FunctorBase') -> bool:
return not self.__eq__(other)
@abstractmethod
def fmap(self, f: Function) -> '_FunctorBase':
raise NotImplementedError
class FunctorWrapper(_FunctorBase):
""" Just a basic wrapping functor for a non-iterable value """
def fmap(self, f: Function) -> 'FunctorWrapper':
return FunctorWrapper()(f(self.value))
我可以证明这些类型满足以下公理(至少对于特定的lambda函数),如Hackage所示,
fmap id == id
fmap (f . g) == fmap f . fmap g
如下:
def id(x: Any) -> Any: return x
def test_functor() -> None:
wrap = FunctorWrapper()(3)
print(wrap.fmap(id))
print(wrap.fmap(lambda x: x + 1))
print(wrap.fmap(lambda x: x + 1).fmap(lambda x: x + 1))
assert wrap.fmap(lambda x: x + 1).fmap(lambda y: y * 2) == \
wrap.fmap(lambda z: (z + 1) * 2), \
'Functor does not satisfy composition axiom'
assert wrap.fmap(id) == wrap, 'Functor does not satisfy identity axiom'
print('** Functor passes all axioms')
test_functor()
# FunctorWrapper(3)
# FunctorWrapper(4)
# FunctorWrapper(5)
# ** Functor passes all axioms
或者,如果您更喜欢可以映射到的类型。以更明确的方式:
class FunctorIterableList(_FunctorBase):
def fmap(self, f: Function) -> 'FunctorIterable':
return FunctorIterableList()(list(map(f, self.value)))
# FunctorIterableList([1, 2, 3, 4])
# FunctorIterableList([2, 3, 4, 5])
# FunctorIterableList([3, 4, 5, 6])
# ** Functor passes all axioms
然而,逆变函子必须满足组合的逆转,
contramap f . contramap g = contramap (g . f)
我不知道如何以这种方式反转Python中的函数组合;我一直在想解决方案可能是在内部将第一个动作存储在类定义中,然后,在第二个调用时,在第一个之前应用第二个动作?必须有一种方法来满足这一要求而不在内部存储这种信息。