Coverage for /home/ubuntu/yoneda/python/yoneda/basic.py: 100%
53 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-08 16:26 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-08 16:26 +0000
1from typing import Callable, Generic, TypeVar # noqa: F401
3import math
5import yoneda.monad as ym
6from yoneda.monad import Monad
8A = TypeVar('A')
9B = TypeVar('B')
10C = TypeVar('C')
11# ------------------------------------------------------------------------------
14class Maybe(Monad, Generic[A]):
15 @classmethod
16 def just(cls, value):
17 # type: (A) -> Maybe[A]
18 '''
19 Just constructor for Maybe class.
21 Args:
22 value (object): Non-null value.
24 Returns:
25 Maybe: Maybe monad of value.
26 '''
27 return cls(value)
29 @classmethod
30 def nothing(cls):
31 # type: () -> Maybe
32 '''
33 Nothing constructor for Maybe class.
35 Returns:
36 Maybe: Nothing monad.
37 '''
38 return cls(None)
40 def __repr__(self):
41 # type: () -> str
42 '''String representation of monad.'''
43 if self.state == 'just':
44 return f'Just({self._data})'
45 return 'Nothing'
47 @property
48 def state(self):
49 # type: () -> str
50 '''State of monad. Either just or nothing.'''
51 data = self._data
52 if data is None or math.isnan(data):
53 return 'nothing'
54 return 'just'
55# ------------------------------------------------------------------------------
58class Try(Monad, Generic[A]):
59 @classmethod
60 def success(cls, value):
61 # type: (A) -> Try[A]
62 '''
63 Success constructor for Try class.
65 Args:
66 value (object): Non-error value.
68 Returns:
69 Maybe: Try monad of value.
70 '''
71 return ym.succeed(cls, value)
73 @classmethod
74 def failure(cls, error):
75 # type: (Exception) -> Try[Exception]
76 '''
77 Success constructor for Try class.
79 Args:
80 error (Exception): Error.
82 Returns:
83 Maybe: Try monad of error.
84 '''
85 return ym.fail(cls, error)
87 def __repr__(self):
88 # type: () -> str
89 '''String representation of monad.'''
90 return f'{self.state.capitalize()}({self._data})'
92 @property
93 def state(self):
94 # type: () -> str
95 '''State of monad. Either success or failure.'''
96 if isinstance(self._data, Exception):
97 return 'failure'
98 return 'success'
100 def fmap(self, func):
101 # type: (Callable[[A], B]) -> Try[B | Exception]
102 '''
103 Functor map: (A -> B) -> MB
105 Given a function A to B, return a Monad of B (MB).
106 Example: m.fmap(lambda x: x + 2)
108 Args:
109 func (function): Function (A -> B).
111 Returns:
112 Try[B]: Try Monad of B.
113 '''
114 try:
115 return super().fmap(func) # type: ignore
116 except Exception as error:
117 return self.fail(error)
119 def bind(self, func):
120 # type: (Callable[[A], Monad[B]]) -> Try[B | Exception]
121 '''
122 Bind: (A -> MB) -> MB
124 Given a function A to MB, return a Monad of B (MB).
126 Args:
127 func (function): Function (A -> MB).
129 Returns:
130 Try[B]: Try Monad of B.
131 '''
132 try:
133 return super().bind(func) # type: ignore
134 except Exception as error:
135 return self.fail(error)
137 def app(self, monad_func):
138 # type: (Monad[Callable[[A], B]]) -> Try[B | Exception]
139 '''
140 Applicative: M(A -> B) -> MB
142 Given a Monad of a function A to B, return a Monad of B (MB).
144 Args:
145 monad_func (Monad): Monad of function (A -> B).
147 Returns:
148 Try[B]: Try Monad of B.
149 '''
150 try:
151 return super().app(monad_func) # type: ignore
152 except Exception as error:
153 return self.fail(error)