Coverage for greyhorse / river / private / monads / reader_t.py: 94%
35 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-18 11:33 +0300
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-18 11:33 +0300
1# mypy: disable_error_code="misc,type-arg,valid-type,override,index,union-attr,attr-defined,arg-type"
2from __future__ import annotations
4from collections.abc import Callable
6from greyhorse.utils.types import TypeWrapper
8from .effect import Effect, ExitCase
11class ReaderT[R, F, T](Effect[T], TypeWrapper[R, F, T]):
12 """Reader monad transformer — lifts an Effect into a Reader context.
14 Wraps ``R -> F[T]`` where ``F`` is an Effect type (typically ``IO``).
15 ``ResourceReader`` extends this with ``Resource[IO, T]`` as the inner Effect.
17 Type parameters:
18 R: Environment (reader context) type.
19 F: Inner Effect type.
20 T: Value type.
21 """
23 __slots__ = ('_run',)
25 def __init__(self, run: Callable[[R], F[T]]) -> None:
26 self._run = run
28 def map[U](self, f: Callable[[F[T]], F[U]]) -> ReaderT[R, F, U]:
29 """Apply a function to the inner Effect."""
30 def run(r: R) -> F[U]:
31 a = self._run(r)
32 return f(a)
34 return ReaderT(run)
36 def and_then[U](self, f: Callable[[F[T]], ReaderT[R, F, U]]) -> ReaderT[R, F, U]:
37 """Monadic bind — chain with a function returning ReaderT."""
38 def run(r: R) -> F[U]:
39 a = self._run(r)
40 return f(a)(r)
42 return ReaderT(run)
44 def __call__(self, r: R) -> F[T]:
45 """Execute with the given environment, returning the inner Effect."""
46 return self._run(r)
48 @classmethod
49 def pure(cls, value: T) -> ReaderT[R, F, T]:
50 """Wrap a pure value into ReaderT using the inner Effect's ``pure``."""
51 return ReaderT(lambda _: cls.__wrapped_type__[1].pure(value))
53 @classmethod
54 def ask(cls) -> ReaderT[R, F, T]:
55 """Return the environment as the value."""
56 return ReaderT(cls.__wrapped_type__[1].pure)
58 def bracket_case[U]( # type: ignore
59 self,
60 use: Callable[[T], ReaderT[R, F, U]],
61 release: Callable[[T, ExitCase], ReaderT[R, F, None]],
62 ) -> ReaderT[R, F, U]:
63 """Acquire-use-release with ExitCase, lifted into ReaderT.
65 Args:
66 use: Function applied to the acquired value.
67 release: Cleanup function with ExitCase feedback.
68 """
69 def run(r: R) -> U:
70 wrapped_acquire = self._run(r)
72 def wrapped_release(v: T, ec: ExitCase) -> F[None]:
73 return release(v, ec)(r)
75 def wrapped_use(v: T) -> F[U]:
76 return use(v)(r)
78 return wrapped_acquire.bracket_case(wrapped_use, wrapped_release)
80 return ReaderT(run)