Coverage for greyhorse / river / private / monads / reader.py: 100%

18 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-05-18 11:33 +0300

1from __future__ import annotations 

2 

3from collections.abc import Callable 

4 

5 

6class Reader[R, T]: 

7 """Reader monad — computation that depends on an environment. 

8 

9 Wraps a function ``R -> T``. Call with an environment to get the result. 

10 

11 Type parameters: 

12 R: Environment (reader context) type. 

13 T: Result type. 

14 

15 Examples: 

16 :: 

17 

18 r = Reader(lambda x: x + 1) 

19 assert r(10) == 11 

20 

21 doubled = r.map(lambda v: v * 2) 

22 assert doubled(10) == 22 

23 

24 chained = r.and_then(lambda v: Reader(lambda r: v * r)) 

25 assert chained(5) == 30 # (5+1) * 5 

26 """ 

27 

28 __slots__ = ('_run',) 

29 

30 def __init__(self, function: Callable[[R], T]) -> None: 

31 self._run = function 

32 

33 def map[U](self, f: Callable[[T], U]) -> Reader[R, U]: 

34 """Apply a pure function to the result.""" 

35 def run(r: R) -> U: 

36 a = self._run(r) 

37 return f(a) 

38 

39 return Reader(run) 

40 

41 def and_then[U](self, f: Callable[[T], Reader[R, U]]) -> Reader[R, U]: 

42 """Monadic bind — chain with a function returning Reader.""" 

43 def run(r: R) -> U: 

44 a = self._run(r) 

45 return f(a)(r) 

46 

47 return Reader(run) 

48 

49 def __call__(self, r: R) -> T: 

50 """Execute the computation with the given environment.""" 

51 return self._run(r)