Skip to content

Instantly share code, notes, and snippets.

@SegFaultAX
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SegFaultAX/f48fe6930d18b52118ab to your computer and use it in GitHub Desktop.
Save SegFaultAX/f48fe6930d18b52118ab to your computer and use it in GitHub Desktop.
Reducers in Python [incomplete]
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