Add Monad.sequence

This commit is contained in:
Correl Roush 2018-12-11 22:08:15 -05:00
parent 83b13a3e74
commit 77bf6b4735
2 changed files with 21 additions and 1 deletions

View file

@ -1,5 +1,6 @@
from __future__ import annotations
from typing import Any, Callable, Generic, TypeVar
import functools
from typing import Any, Callable, Generic, Iterable, List, TypeVar
from .applicative import Applicative
from .functor import Functor
@ -16,4 +17,17 @@ class Monad(Applicative[T]):
def bind(self, function: Callable[[T], Any]) -> Monad[S]: # pragma: no cover
raise NotImplementedError
@classmethod
def pure(cls, value: T) -> Monad[T]:
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([]))
__rshift__ = bind

View file

@ -41,3 +41,9 @@ def test_associativity(monad) -> None:
return monad.pure(n + 5)
assert m.bind(f).bind(g) == m.bind(lambda x: f(x).bind(g))
def test_sequence(monad) -> None:
assert monad.pure([1, 2, 3]) == monad.sequence(
[monad.pure(1), monad.pure(2), monad.pure(3)]
)