26
26
27
27
"""
28
28
29
- from typing import Any , Generic , List , TypeVar , Union # pylint: disable=unused-import
29
+ from typing import (
30
+ Any ,
31
+ Generic ,
32
+ List ,
33
+ TypeVar ,
34
+ Union ,
35
+ Iterable ,
36
+ Self ,
37
+ ) # pylint: disable=unused-import
30
38
31
- T = TypeVar ('T' ) # pylint: disable=invalid-name
32
- MonoidT = Union ['Monoid[T]' , '_MonoidIdentity' ]
39
+ T = TypeVar ("T" ) # pylint: disable=invalid-name
33
40
34
- class Monoid (Generic [T ]):
41
+
42
+ class Monoid [T ]:
35
43
"""Base class for Monoid instances.
36
44
37
45
To implement a monoid instance, create a sub-class of Monoid and
@@ -40,19 +48,31 @@ class Monoid(Generic[T]):
40
48
41
49
"""
42
50
51
+ @classmethod
52
+ def wrap (cls , value : T ) -> Self :
53
+ if value == None :
54
+ return cls .identity_element ()
55
+ return cls (value )
56
+
43
57
def __init__ (self , value : T ) -> None :
58
+ if value == None :
59
+ raise ValueError ("None Objects not allowed in Monoids" )
44
60
self .value = value
45
61
46
- def __add__ (self : MonoidT , other : MonoidT ) -> MonoidT :
62
+ def __add__ (self , other : Self | T ) -> Self :
63
+ if not isinstance (other , self .__class__ ):
64
+ if isinstance (other , Monoid ):
65
+ raise ValueError ("Incompatible Monoid" )
66
+ return self .addition_operation (self .__class__ (other ))
47
67
return self .addition_operation (other )
48
68
49
69
def __eq__ (
50
- self : Union [' _MonoidIdentity' , ' Monoid[T]' ],
51
- other : Union [' _MonoidIdentity' , ' Monoid[T]' ]
70
+ self : Union [" _MonoidIdentity" , " Monoid[T]" ],
71
+ other : Union [" _MonoidIdentity" , " Monoid[T]" ],
52
72
) -> bool :
53
73
return self .value == other .value
54
74
55
- def addition_operation (self : MonoidT , other : MonoidT ) -> MonoidT :
75
+ def addition_operation (self : Self , other : Self ) -> Self :
56
76
"""Defines how monoid values are added together.
57
77
58
78
addition_operation() method is automatically called by
@@ -70,36 +90,64 @@ def addition_operation(self: MonoidT, other: MonoidT) -> MonoidT:
70
90
"""
71
91
raise NotImplementedError
72
92
73
- @staticmethod
74
- def identity_element ( ) -> 'Monoid[Any]' :
93
+ @classmethod
94
+ def identity_element [ a : "Monoid" ]( cls : type [ a ] ) -> a :
75
95
"""Returns the identity value for the monoid type.
76
96
77
- This method must be overridden in subclasses of Monoid.
97
+ This method must be overridden in subclasses of Monoid
78
98
79
99
"""
80
100
raise NotImplementedError
81
101
82
- class _MonoidIdentity :
102
+
103
+ # class _MonoidIdentity[a : Monoid](a): #once Python Types has those features, this is what we want
104
+ class _MonoidIdentity [T ](Monoid [T ]):
105
+ superclass = Monoid
106
+
83
107
def __init__ (self ):
108
+ found = False
109
+ for i in type (self ).__mro__ :
110
+ if (
111
+ i != _MonoidIdentity
112
+ and i != self .__class__
113
+ and i != Monoid
114
+ and i != Generic
115
+ and i != object
116
+ ):
117
+ self .superclass = i
118
+ found = True
119
+ break
120
+ if not found and self .__class__ != _MonoidIdentity :
121
+ raise Exception ("no superclass found" )
84
122
self .value = None
85
123
86
- def __add__ (self , other ):
124
+ def __add__ (self : Self , other : Monoid [T ] | T ):
125
+ if not isinstance (other , Monoid ):
126
+ return self .superclass (other )
87
127
return other
88
128
89
- def __radd__ (self , other ):
129
+ def __radd__ (self , other : Self ):
130
+ if not isinstance (other , Monoid ):
131
+ return self .superclass (other )
90
132
return other
91
133
92
134
def __repr__ (self ):
93
- return 'IDENTITY'
135
+ return "IDENTITY"
136
+
94
137
95
138
IDENTITY = _MonoidIdentity ()
96
139
97
- def mconcat (monoid_list : List [MonoidT ]) -> MonoidT :
140
+
141
+ # mconcat([Monoida, Monoidb]) not throws an error :nice
142
+ def mconcat [a : Monoid ](monoid_list : Iterable [a ]) -> a :
98
143
"""Takes a list of monoid values and reduces them to a single value
99
144
by applying the '+' operation to all elements of the list.
100
-
145
+ Needs a non empty list, because Python doesn't allow calling on types
101
146
"""
102
- result = monoid_list [0 ]
103
- for value in monoid_list :
104
- result += value
147
+ it = monoid_list .__iter__ ()
148
+
149
+ # a.identity()
150
+ result = it .__next__ ()
151
+ for value in it :
152
+ result = result + value
105
153
return result
0 commit comments