fixed a typo...
[pli.git] / pli / functional.py
blob798b05728123f9d2876ebeee2ab055f52261d496
1 #=======================================================================
3 __version__ = '''0.5.14'''
4 __sub_version__ = '''20061124145258'''
5 __copyright__ = '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 ##from __future__ import generators
11 import new
13 ##import pli.pattern.proxy as proxy
16 #-----------------------------------------------------------------------
17 #---------------------------------------------------------------apply---
18 apply = lambda func, *pargs, **nargs: func(*pargs, **nargs)
21 #--------------------------------------------------------------lcurry---
22 lcurry = lambda func, *pargs, **nargs:\
23 lambda *p, **n:\
24 func(*pargs + p, **dict(nargs.items() + n.items()))
27 #---------------------------------------------------------------curry---
28 curry = lcurry
31 #--------------------------------------------------------------rcurry---
32 # NOTE: this adds the curried args to the tail...
33 rcurry = lambda func, *pargs, **nargs:\
34 lambda *p, **n:\
35 func(*p + pargs, **dict(nargs.items() + n.items()))
38 #-----------------------------------------------------------fastcurry---
39 # Originally written by Alex Martelli
40 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/229472
41 # NOTE: though this is faster, it is also less flexible than the above
42 # variants.
43 # NOTE: here 'arg' can not be None.
44 fastcurry = lambda func, arg:\
45 new.instancemethod(func, arg, object)
48 #-------------------------------------------------------AbstractCurry---
49 class AbstractCurry(object):
50 '''
51 '''
52 pass
55 #--------------------------------------------------------------LCurry---
56 class LCurry(AbstractCurry):
57 '''
58 this is the left curry class.
59 '''
60 def __new__(cls, func, *args, **kw):
61 obj = object.__new__(cls)
62 if isinstance(func, AbstractCurry):
63 obj._curry_func = func._curry_func
64 obj._curry_args = (func._curry_args[0] + args, func._curry_args[1])
65 obj._curry_kw = kw = kw.copy()
66 kw.update(func._curry_kw)
67 else:
68 obj._curry_func = func
69 obj._curry_args = (args, ())
70 obj._curry_kw = kw.copy()
71 return obj
72 def __call__(self, *args, **kw):
73 return self._curry_func(*self._curry_args[0] + args + self._curry_args[1], \
74 **dict(self._curry_kw.items() + kw.items()))
77 #---------------------------------------------------------------Curry---
78 Curry = LCurry
81 #--------------------------------------------------------------RCurry---
82 class RCurry(AbstractCurry):
83 '''
84 this is the right curry class.
85 '''
86 def __new__(cls, func, *args, **kw):
87 obj = object.__new__(cls)
88 if isinstance(func, AbstractCurry):
89 obj._curry_func = func._curry_func
90 obj._curry_args = (func._curry_args[0], func._curry_args[1] + args)
91 obj._curry_kw = kw = kw.copy()
92 kw.update(func._curry_kw)
93 else:
94 obj._curry_func = func
95 obj._curry_args = ((), args)
96 obj._curry_kw = kw.copy()
97 return obj
98 def __call__(self, *args, **kw):
99 return self._curry_func(*self._curry_args[0] + args + self._curry_args[1],
100 **dict(self._curry_kw.items() + kw.items()))
103 #---------------------------------------------------------LCurryProxy---
104 ##!!! TEST !!!##
105 ##class LCurryProxy(AbstractCurry, proxy.TransparentInheritAndOverrideProxy):
106 ## '''
107 ## '''
108 ## def __init__(self, target, *p, **n):
109 ## '''
110 ## '''
111 ## # handle recursive curry....
112 ## if hasattr(target, '_curry_pargs'):
113 ## p = p + target._curry_pargs
114 ## if hasattr(target, '_curry_kw'):
115 ## n = dict(n.items() + target._curry_kw.items())
116 ## # assign the args...
117 ## self._curry_pargs = p
118 ## # XXX do we need to copy the dict???
119 ## self._curry_kw = n
120 ## def __call__(self, *p, **n):
121 ## '''
122 ## '''
123 ## super(CurryProxy, self).__call__(*(p + self._curry_pargs), \
124 ## **dict(n.items() + self._curry_kw.items()))
127 #---------------------------------------------------------RCurryProxy---
128 ##!!! TEST !!!##
129 ##class RCurryProxy(AbstractCurry, proxy.TransparentInheritAndOverrideProxy):
130 ## '''
131 ## '''
132 ## def __init__(self, target, *p, **n):
133 ## '''
134 ## '''
135 ## # handle recursive curry....
136 ## if hasattr(target, '_curry_pargs'):
137 ## p = target._curry_pargs + p
138 ## if hasattr(target, '_curry_kw'):
139 ## n = dict(n.items() + target._curry_kw.items())
140 ## # assign the args...
141 ## self._curry_pargs = p
142 ## # XXX do we need to copy the dict???
143 ## self._curry_kw = n
144 ## def __call__(self, *p, **n):
145 ## '''
146 ## '''
147 ## super(CurryProxy, self).__call__(*(self._curry_pargs + p), \
148 ## **dict(n.items() + self._curry_kw.items()))
151 #--------------------------------------------------------------negate---
152 # this will return a function that will return the oposite result
153 # (boolean) to the original....
154 negate = lambda f:\
155 lambda *p, **n: not f(*p, **n)
158 #------------------------------------------------------raise_on_false---
159 def raise_on_false(func, exception=Exception, name=None, msg=''):
161 this will return a function wraping func so as to raise exception(msg) if it returns false.
163 # sanity checks...
164 if func == None:
165 raise TypeError, 'func must not be None.'
166 if hasattr(func, '_raise_on_false_wrapped') and func._raise_on_false_wrapped:
167 raise TypeError, '%s is already wrapped, won\'t wrap agen.' % func
169 # define the function code...
170 func_txt = """def %(function_name)s(*p, **n):
171 '''wrapper of %(function_object)s callable.'''
172 res = func(*p, **n)
173 if not res:
174 raise exception, msg
175 return res"""
176 # genreate a good name if one is not given...
177 if name == None:
178 name = hasattr(func, '__name__') and func.__name__ != '<lambda>' and func.__name__ or 'Unnamed'
179 exec (func_txt % {'function_name':name, 'function_object':func}) in locals(), globals()
180 f = eval(name)
181 # marck the predicate returned... (to avoid repeated wrapping (see
182 # above))...
183 f._raise_on_false_wrapped = True
184 return f
187 ###------------------------------------------------------------iterator---
188 ##class _iterator(object):
189 ## '''
190 ## '''
191 ## def __init__(self, iter_next, iter_init, *p, **n):
192 ## '''
193 ## '''
194 ## init(self, *p, **n)
195 ## self.next = new.instancemethod(iter_next, self, iterator)
196 ## def __iter__(self):
197 ## return self
201 #-----------------------------------------------------------------------
202 ##!! THE FOLLOWING ARE EXPERIMENTAL !!##
203 #-----------------------------------------------------------------seq---
204 def seq(f0, *f):
206 seq(f0[, f1[, ...]]) -> res
207 seq(name, f0[, f1[, ...]]) -> res
209 this will return a function that when called will sequence the functions given,
210 passing its arguments into each one, and returning the list of their results.
212 NOTE: in the second form the name is used as name for the resulting function.
213 NOTE: atleast one function must be given.
215 if type(f0) is str:
216 if len(f) < 1:
217 raise TypeError, 'need atleast one callable in the sequence (got: 0).'
219 func_txt = """def %(function_name)s(*p, **n):
220 '''sequence wrapper of %(functions)s.'''
221 res = []
222 for func in f:
223 res += [func(*p, **n)]
224 return res"""
225 exec (func_txt % {'function_name':f0, 'functions':f}) in locals(), globals()
226 _seq = eval(f0)
227 else:
228 def _seq(*p, **n):
231 res = []
232 for func in (f0,) + f:
233 res += [func(*p, **n)]
234 return res
235 return _seq
239 #-----------------------------------------------------------------------
240 #--------------------------------------------------------getclasstree---
241 def getclasstree(cls, predicate=None):
242 l = []
243 for c in cls.__subclasses__():
244 if predicate != None and predicate(c):
245 l += [(c, getclasstree(c, predicate))]
246 elif predicate == None:
247 l += [(c, getclasstree(c))]
248 return l
251 #---------------------------------------------------classtreeiterdown---
252 # this is my first recursive iterator... :)
253 def classtreeiterdown(cls, predicate=None):
255 this will iterate the inheritance tree branch down.
257 for c in cls.__subclasses__():
258 if predicate != None and predicate(c):
259 yield c
260 for cls in classtreeiterdown(c, predicate):
261 yield cls
262 elif predicate == None:
263 yield c
264 for cls in classtreeiterdown(c):
265 yield cls
268 #-----------------------------------------------------classtreeiterup---
269 def classtreeiterup(cls, predicate=None):
271 this will iterate the inheritance tree up.
273 NOTE: this will not remove duplicate classes.
275 for c in cls.__bases__:
276 if predicate != None and predicate(c):
277 yield c
278 for cls in classtreeiterup(c, predicate):
279 yield cls
280 elif predicate == None:
281 yield c
282 for cls in classtreeiterup(c):
283 yield cls
287 #=======================================================================
288 # vim:set ts=4 sw=4 nowrap :