Skip to content

Future

funstruct.monad.future

Future — lazy async computation.

Future[A] wraps Awaitable[A]. A generic async monad — no error semantics built in. For error handling, use AsyncResult[A] from funstruct.monad.result.

Future

Bases: DataType, Generic[A]

Lazy async computation that produces A when awaited.

Source code in funstruct/monad/future/__init__.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Future(DataType, Generic[A]):
    """Lazy async computation that produces A when awaited."""

    def __init__(self, coro: Awaitable[A]) -> None:
        self._coro = ReAwaitable(coro) if not isinstance(coro, ReAwaitable) else coro

    def __del__(self):
        pass

    def __await__(self) -> Generator[None, None, A]:
        return self._awaitable().__await__()

    async def _awaitable(self) -> A:
        return await self._coro

    def bind(self, f: Callable[[A], Future[B]]) -> Future[B]:
        async def _inner():
            result = await self._coro
            return await f(result)

        return Future(_inner())

    @classmethod
    def do(cls, gen_fn: Callable) -> Callable[..., Future]:
        """Do-notation for Future.

        >>> @Future.do
        ... def pipeline():
        ...     x = yield Future.pure(1)
        ...     y = yield Future.pure(x + 10)
        ...     return x + y
        """

        def _thunk(*args, **kwargs):
            async def _run():
                gen = gen_fn(*args, **kwargs)
                try:
                    monadic_val = next(gen)
                    while True:
                        value = await monadic_val
                        monadic_val = gen.send(value)
                except StopIteration as e:
                    return e.value

            return cls(_run())

        return _thunk

    @classmethod
    def pure(cls, value: A) -> Future[A]:
        async def _inner():
            return value

        return cls(_inner())

    def __repr__(self) -> str:
        return f"Future({self._coro})"

do(gen_fn) classmethod

Do-notation for Future.

@Future.do ... def pipeline(): ... x = yield Future.pure(1) ... y = yield Future.pure(x + 10) ... return x + y

Source code in funstruct/monad/future/__init__.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@classmethod
def do(cls, gen_fn: Callable) -> Callable[..., Future]:
    """Do-notation for Future.

    >>> @Future.do
    ... def pipeline():
    ...     x = yield Future.pure(1)
    ...     y = yield Future.pure(x + 10)
    ...     return x + y
    """

    def _thunk(*args, **kwargs):
        async def _run():
            gen = gen_fn(*args, **kwargs)
            try:
                monadic_val = next(gen)
                while True:
                    value = await monadic_val
                    monadic_val = gen.send(value)
            except StopIteration as e:
                return e.value

        return cls(_run())

    return _thunk