2018-10-11 05:26:00 +00:00
|
|
|
from __future__ import annotations
|
2018-12-12 03:08:15 +00:00
|
|
|
import functools
|
|
|
|
from typing import Any, Callable, Generic, Iterable, List, TypeVar
|
2018-10-11 05:26:00 +00:00
|
|
|
|
2018-10-12 18:09:16 +00:00
|
|
|
from .applicative import Applicative
|
2018-10-11 05:26:00 +00:00
|
|
|
from .functor import Functor
|
|
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
S = TypeVar("S")
|
|
|
|
|
|
|
|
|
2018-10-12 18:09:16 +00:00
|
|
|
class Monad(Applicative[T]):
|
2018-10-11 05:26:00 +00:00
|
|
|
# FIXME: Callable return type set to Any, as the proper value
|
|
|
|
# (Monad[S]) is reported as incompatible with subclass
|
|
|
|
# implementations due to a flaw in mypy:
|
|
|
|
# https://github.com/python/mypy/issues/1317
|
2018-10-12 18:24:03 +00:00
|
|
|
def bind(self, function: Callable[[T], Any]) -> Monad[S]: # pragma: no cover
|
2018-10-11 05:26:00 +00:00
|
|
|
raise NotImplementedError
|
2018-12-06 18:53:07 +00:00
|
|
|
|
2018-12-12 03:08:15 +00:00
|
|
|
@classmethod
|
2018-12-12 06:17:49 +00:00
|
|
|
def pure(cls, value: T) -> Monad[T]: # pragma: no cover
|
2018-12-12 03:08:15 +00:00
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def sequence(cls, xs: Iterable[Monad[T]]) -> Monad[List[T]]:
|
|
|
|
"""Evaluate monadic actions in sequence, collecting results."""
|
|
|
|
|
|
|
|
def reducer(acc: Monad[List[T]], x: Monad[T]) -> Monad[List[T]]:
|
|
|
|
return acc.bind(lambda acc_: x.map(lambda x_: acc_ + [x_]))
|
|
|
|
|
|
|
|
return functools.reduce(reducer, xs, cls.pure([]))
|
|
|
|
|
2018-12-06 18:53:07 +00:00
|
|
|
__rshift__ = bind
|