Last active
August 29, 2015 14:05
-
-
Save SegFaultAX/f48fe6930d18b52118ab to your computer and use it in GitHub Desktop.
Reducers in Python [incomplete]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import copy | |
class ReducedException(Exception): | |
def __init__(self, reduced_value): | |
super(ReducedException, self).__init__() | |
self.reduced_value = reduced_value | |
def conj(coll, *es): | |
"""Conjoin elements to coll. Works correctly for most collection types""" | |
if coll is None: | |
return list(es) | |
elif isinstance(coll, list): | |
return coll + list(es) | |
elif isinstance(coll, tuple): | |
return coll + tuple(es) | |
elif isinstance(coll, set): | |
return coll | set(es) | |
elif isinstance(coll, basestring): | |
return "".join([coll] + list(es)) | |
elif isinstance(coll, dict): | |
coll2 = copy.copy(coll) | |
coll2.update(es) | |
return coll2 | |
else: | |
raise ValueError("No conj implementation for %s" % type(coll)) | |
def seq(coll): | |
"""Convert a collection into an iterator""" | |
if coll is None: | |
return iter([]) | |
elif isinstance(coll, (list, tuple, set, basestring)): | |
return iter(coll) | |
elif isinstance(coll, dict): | |
return coll.iteritems() | |
else: | |
raise ValueError("No seq implementation for %s" % type(coll)) | |
def first(coll): | |
"""Get the first element of `coll`""" | |
s = seq(coll) | |
try: | |
return s.next() | |
except StopIteration: | |
return None | |
def rest(coll): | |
"""Get the remaining elements of `coll`""" | |
s = seq(coll) | |
try: | |
s.next() | |
return s | |
except StopIteration: | |
return None | |
def reduced(val): | |
"""Exit a reducing function before the entire collection has been consumed""" | |
raise ReducedException(val) | |
def reduce(f, coll, init=None): | |
def fold(f, init, it): | |
try: | |
for e in it: | |
init = f(init, e) | |
return init | |
except ReducedException as e: | |
return e.reduced_value | |
if init is None: | |
return fold(f, first(coll), rest(coll)) | |
else: | |
return fold(f, init, seq(coll)) | |
def mapping(f): | |
def mapper(f1): | |
def apply(result, v): | |
return f1(result, f(v)) | |
return apply | |
return mapper | |
def filtering(f): | |
def filterer(f1): | |
def apply(result, v): | |
return f1(result, v) if f(v) else result | |
return apply | |
return filterer | |
def mapcatting(f): | |
def mapcatter(f1): | |
def apply(result, v): | |
return reduce(f1, f(v), result) | |
return apply | |
return mapcatter | |
ident = lambda n: n | |
add = lambda *xs: 0 if len(xs) == 0 else sum(xs) | |
mul = lambda *xs: 1 if len(xs) == 0 else reduce(lambda a, b: a * b, xs) | |
inc = lambda n: n + 1 | |
dec = lambda n: n - 1 | |
even = lambda n: n % 2 == 0 | |
juxt = lambda *fns: lambda e: [fn(e) for fn in fns] | |
print reduce(mapping(inc)(conj), [1,2,3,4], []) | |
print reduce(filtering(even)(conj), [1,2,3,4], []) | |
print reduce(mapcatting(juxt(inc, dec))(conj), [1,2,3,4], []) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment