Initial checkin
[ejpi] / src / libraries / recipes / operators.py
1 #!/usr/bin/env python
2
3 """
4 Example Operators for comparison
5 >>> class C(object):
6 ...     def __init__(self, x):
7 ...         self.x = x
8 ...
9 >>> x, y, z = C(1), C(1), C(2)
10 >>> x == y, hash(x) == hash(y)
11 (False, False)
12 """
13
14
15 import operator
16 import itertools
17
18
19 class KeyedEqualityOperators(object):
20         """
21         Mixin for auto-implementing comparison operators
22         @note Requires inheriting class to implement a '__key__' function
23         Example:
24         >>> class C(KeyedEqualityOperators):
25         ...     def __init__(self, x):
26         ...         self.x = x
27         ...     def __key__(self):
28         ...         return self.x
29         ...
30         >>> x, y, z = C(1), C(1), C(2)
31         >>> x == y, hash(x) == hash(y)
32         (True, False)
33         """
34
35         def __init__(self):
36                 self.__key__ = None
37
38         def __eq__(self, other):
39                 return self.__key__() == other.__key__()
40
41         def __ne__(self, other):
42                 return self.__key__() != other.__key__()
43
44
45 class KeyedComparisonOperators(KeyedEqualityOperators):
46         """
47         Mixin for auto-implementing comparison operators
48         @note Requires inheriting class to implement a '__key__' function
49         Example:
50         >>> class C(KeyedComparisonOperators):
51         ...     def __init__(self, x):
52         ...         self.x = x
53         ...     def __key__(self):
54         ...         return self.x
55         ...
56         >>> x, y, z = C(1), C(1), C(2)
57         >>> x == y, y < z, hash(x) == hash(y)
58         (True, True, False)
59         """
60
61         def __init__(self):
62                 self.__key__ = None
63
64         def __cmp__(self, other):
65                 return cmp(self.__key__(), other.__key__())
66
67         def __lt__(self, other):
68                 return self.__key__() < other.__key__()
69
70         def __le__(self, other):
71                 return self.__key__() <= other.__key__()
72
73         def __gt__(self, other):
74                 return self.__key__() > other.__key__()
75
76         def __ge__(self, other):
77                 return self.__key__() >= other.__key__()
78
79
80 class KeyedHashing(object):
81         """
82         Mixin for auto-implementing comparison operators
83         @note Requires inheriting class to implement a '__key__' function
84         Example:
85         >>> class C(KeyedHashing):
86         ...     def __init__(self, x):
87         ...         self.x = x
88         ...     def __key__(self):
89         ...         return self.x
90         ...
91         >>> x, y, z = C(1), C(1), C(2)
92         >>> x == y, hash(x) == hash(y)
93         (False, True)
94         """
95
96         def __init__(self):
97                 self.__key__ = None
98
99         def __hash__(self):
100                 return hash(self.__key__())
101
102
103 class NotEqualOperator(object):
104         """
105         Mixin for auto-implementing comparison operators
106         @note Requires inheriting class to implement '__eq__' function
107         """
108
109         def __ne__(self, other):
110                 return not (self == other)
111
112
113 class ComparisonOperators(NotEqualOperator):
114         """
115         Mixin for auto-implementing comparison operators
116         @note Requires inheriting class to implement '__lt__' function
117         """
118
119         def __le__(self, other):
120                 return(self < other) or(self == other)
121
122         def __gt__(self, other):
123                 return not(self <= other)
124
125         def __ge__(self, other):
126                 return not(self < other)
127
128
129 class infix(object):
130         """
131         Recipe #384122
132         http://code.activestate.com/recipes/384122/
133
134         >>> import operator
135         >>> x = infix(operator.mul)
136         >>> 1 |x| 2 |x| 10
137         20
138         """
139
140         def __init__(self, func):
141                 self.__name__ = func.__name__
142                 self.__doc__ = func.__doc__
143                 try:
144                         self.__dict__.update(func.__dict__)
145                 except AttributeError:
146                         pass
147                 self.function = func
148
149         def __ror__(self, other):
150                 return infix(lambda x: self.function(other, x))
151
152         def __or__(self, other):
153                 return self.function(other)
154
155         def __call__(self, lhs, rhs):
156                 return self.function(lhs, rhs)
157
158
159 class Just(object):
160         """
161         @see mreturn
162         """
163
164         def __init__(self, value):
165                 self.value = value
166
167
168 @infix
169 def mbind(maybe, func):
170         """
171         @see mreturn
172         """
173         if maybe is None:
174                 return None
175         else:
176                 return func(maybe.value)
177
178
179 def mreturn(value):
180         """
181         >>> class Sheep(object):
182         ...     def __init__(self, name):
183         ...             self.name = name
184         ...             self.mother = None
185         ...             self.father = None
186         ...
187         >>> def father(sheep):
188         ...     if sheep.father is None:
189         ...             return None
190         ...     else:
191         ...             return Just(sheep.father)
192         ...
193         >>> def mother(sheep):
194         ...     if sheep.mother is None:
195         ...             return None
196         ...     else:
197         ...             return Just(sheep.mother)
198         ...
199         >>> def mothersFather(sheep):
200         ...     return mreturn(sheep) |mbind| mother |mbind| father
201         ...
202         >>> def mothersPaternalGrandfather(sheep):
203         ...     return mreturn(sheep) |mbind| mother |mbind| father |mbind| father
204         ...
205         >>> shawn = Sheep("Shawn")
206         >>> gertrude = Sheep("Gertrude")
207         >>> ernie = Sheep("Ernie")
208         >>> frank = Sheep("Frank")
209         >>>
210         >>> shawn.mother = gertrude
211         >>> gertrude.father = ernie
212         >>> ernie.father = frank
213         >>>
214         >>> print mothersFather(shawn).value.name
215         Ernie
216         >>> print mothersPaternalGrandfather(shawn).value.name
217         Frank
218         >>> print mothersPaternalGrandfather(ernie)
219         None
220         """
221         return Just(value)
222
223
224 def xor(*args):
225         truth = itertools.imap(operator.truth, args)
226         return reduce(operator.xor, truth)
227
228
229 def equiv(*args):
230         truth = itertools.imap(operator.truth, args)
231         return reduce(lambda a, b: not operator.xor(a, b), truth)