@dataclass
class Writer(Generic[W, V]):
"""Writer is a monad."""
value: V
written: W
# @staticmethod
# def pure(a: E, m: Type[Monoid[T]]) -> Writer[T, E]:
# def pure(a: E, m: Type[T]) -> Writer[T, E]:
# return Writer(a, m.empty())
# return Writer(a, cast(T, m.empty()))
# @staticmethod
# def pure(a: E) -> Writer[W, E]:
# w: W
# wt = type(w)
# return Writer(a, monoid_empty(wt))
def pure(self, a: E) -> Writer[W, E]:
if isinstance(self.written, int):
return Writer(a, cast(W, 0))
else:
return Writer(a, cast(Monoid, self.written).empty())
@staticmethod
def pure2(a: E, m: T) -> Writer[T, E]:
return Writer(a, m)
def fmap(self, f: Callable[[V], B]) -> Writer[W, B]:
return Writer(f(self.value), self.written)
def flatmap(self, f: Callable[[V], Writer[W, B]]) -> Writer[W, B]:
new_writer = f(self.value)
new_written = cast(W, self.written + new_writer.written)
return Writer(new_writer.value, new_written)
def ap(self: Writer[W, Callable[[C], E]],
other: Writer[W, C]) -> Writer[W, E]:
return other.fmap(self.value)