1
1
# -*- coding: utf-8 -*-
2
2
3
- from typing import Callable , NoReturn
3
+ from abc import ABCMeta , abstractmethod
4
+ from typing import Callable , NoReturn , Generic , TypeVar , Any , Union , NewType
5
+ from typing_extensions import Protocol
4
6
5
7
from dry_monads .primitives .exceptions import UnwrapFailedError
6
- from dry_monads .primitives .monad import Monad , NewValueType , ValueType
8
+ from dry_monads .primitives .monad import NewValueType , ValueType , Monad
7
9
10
+ ErrorType = TypeVar ('ErrorType' )
8
11
9
- class Either (Monad [ValueType ]):
12
+
13
+ class Either (Generic [ValueType , ErrorType ]):
10
14
"""
11
15
Represents a calculation that may either fail or succeed.
12
16
13
17
An alternative to using exceptions.
14
18
'Either' (or its alias 'Result') is an abstract type and should not
15
19
be instantiated directly. Instead use 'Right' (or its alias 'Success')
16
- and 'Left' (or its alias 'Failure')
20
+ and 'Left' (or its alias 'Failure').
17
21
"""
18
22
23
+ _inner_value : Union [ValueType , ErrorType ]
24
+
25
+ @abstractmethod
26
+ def unwrap (self ) -> ValueType :
27
+ """
28
+ Custom magic method to unwrap inner value from monad.
29
+
30
+ Should be redefined for ones that actually have values.
31
+ And for ones that raise an exception for no values.
32
+ """
33
+ raise NotImplementedError ()
34
+
19
35
20
- class Left (Either [ValueType ]):
36
+ class Left (Either [Any , ErrorType ], Monad [ ErrorType ]):
21
37
"""
22
38
Represents a calculation which has failed.
23
39
24
40
It should contain an error code or message.
25
41
To help with readability you may alternatively use the alias 'Failure'.
26
42
"""
27
43
28
- def fmap (self , function ) -> 'Left[ValueType]' :
44
+ def __init__ (self , inner_value : ErrorType ) -> None :
45
+ """
46
+ Wraps the given value in the Container.
47
+
48
+ 'value' is any arbitrary value of any type including functions.
49
+ """
50
+ self ._inner_value = inner_value
51
+
52
+ def fmap (self , function ) -> 'Left[ErrorType]' :
29
53
"""Returns the 'Left' instance that was used to call the method."""
30
54
return Left (self ._inner_value )
31
55
32
- def bind (self , function ) -> 'Left[ValueType ]' :
56
+ def bind (self , function ) -> 'Left[ErrorType ]' :
33
57
"""Returns the 'Left' instance that was used to call the method."""
34
58
return Left (self ._inner_value )
35
59
@@ -42,13 +66,21 @@ def unwrap(self) -> NoReturn:
42
66
raise UnwrapFailedError (self )
43
67
44
68
45
- class Right (Either [ValueType ]):
69
+ class Right (Either [ValueType , Any ], Monad [ ValueType ]):
46
70
"""
47
71
Represents a calculation which has succeeded and contains the result.
48
72
49
73
To help with readability you may alternatively use the alias 'Success'.
50
74
"""
51
75
76
+ def __init__ (self , inner_value : ValueType ) -> None :
77
+ """
78
+ Wraps the given value in the Container.
79
+
80
+ 'value' is any arbitrary value of any type including functions.
81
+ """
82
+ self ._inner_value = inner_value
83
+
52
84
def fmap (
53
85
self ,
54
86
function : Callable [[ValueType ], NewValueType ],
@@ -65,8 +97,8 @@ def fmap(
65
97
66
98
def bind (
67
99
self ,
68
- function : Callable [[ValueType ], Either [NewValueType ]],
69
- ) -> Either [NewValueType ]:
100
+ function : Callable [[ValueType ], Either [NewValueType , ErrorType ]],
101
+ ) -> Either [NewValueType , ErrorType ]:
70
102
"""
71
103
Applies 'function' to the result of a previous calculation.
72
104
@@ -89,3 +121,11 @@ def unwrap(self) -> ValueType:
89
121
Result = Either
90
122
Success = Right
91
123
Failure = Left
124
+
125
+ # def function(trigger: int) -> Either[int, bool]:
126
+ # if trigger > 1:
127
+ # reveal_type(Success(''))
128
+ # return Success('')
129
+ # else:
130
+ # reveal_type(Failure(''))
131
+ # return Failure('-')
0 commit comments