typesafe-monads/monads/future.py

69 lines
2.1 KiB
Python
Raw Normal View History

2018-12-13 03:50:27 +00:00
from __future__ import annotations
import functools
from typing import Awaitable, Callable, Iterable, List, TypeVar, Union
2018-12-13 03:50:27 +00:00
from .monad import Monad
T = TypeVar("T")
S = TypeVar("S")
class Future(Monad[T]):
"""Wraps an Awaitable in a Monad.
The resulting Future object is, itself, Awaitable.
"""
def __init__(self, awaitable: Awaitable[T]) -> None:
self.awaitable = awaitable
@classmethod
def pure(cls, value: T) -> Future[T]:
async def identity(x: T) -> T:
return x
2018-12-13 03:50:27 +00:00
return Future(identity(value))
2018-12-13 03:50:27 +00:00
def map(self, function: Callable[[T], S]) -> Future[S]:
async def map(f: Callable[[T], S], x: Awaitable[T]) -> S:
x_ = await x
return f(x_)
return Future(map(function, self.awaitable))
def apply(self, functor: Awaitable[Callable[[T], S]]) -> Future[S]:
async def apply(f: Awaitable[Callable[[T], S]], x: Awaitable[T]) -> S:
f_ = await f
x_ = await x
return f_(x_)
return Future(apply(functor, self.awaitable))
def bind(self, function: Callable[[T], Awaitable[S]]) -> Future[S]:
async def bind(f: Callable[[T], Awaitable[S]], x: Awaitable[T]) -> S:
x_ = await x
y = await function(x_)
return y
return Future(bind(function, self.awaitable))
@classmethod
def sequence(cls, xs: Iterable[Awaitable[T]]) -> Future[List[T]]:
"""Evaluate monadic actions in sequence, collecting results."""
def mcons(acc: Future[List[T]], x: Awaitable[T]) -> Future[List[T]]:
future: Future[T] = x if isinstance(x, Future) else Future(x)
return acc.bind(lambda acc_: future.map(lambda x_: acc_ + [x_]))
empty: Future[List[T]] = cls.pure([])
return functools.reduce(mcons, xs, empty)
2018-12-13 03:50:27 +00:00
def __await__(self):
return self.awaitable.__await__()
2019-01-23 04:44:02 +00:00
def __repr__(self):
return f"<Future {self.awaitable}>"
2018-12-13 03:50:27 +00:00
__rshift__ = bind
__and__ = lambda other, self: Future.apply(self, other)
__mul__ = __rmul__ = map