Skip to content

Instantly share code, notes, and snippets.

@viksit
Created September 19, 2014 18:25
Show Gist options
  • Save viksit/223dfafe84c54e75deef to your computer and use it in GitHub Desktop.
Save viksit/223dfafe84c54e75deef to your computer and use it in GitHub Desktop.
transducers in python via @ colin_
summer = lambda acc, val: acc+val
maxxer = lambda acc, val: max(acc, val)
unioner = lambda acc, val: acc.union({val})
def log(val):
print 'value:', val
return val
print reduce(summer, xrange(5), 0)
print reduce(maxxer, xrange(5), 0)
mapper = lambda f: lambda reducer: lambda acc, val: reducer(acc, f(val))
filterer = lambda f: lambda reducer: lambda acc, val: reducer(acc, val) if f(val) else acc
logger = mapper(log)
even = lambda x: x % 2 == 0
odd = lambda x: not even(x)
double = lambda x: 2 * x
inc = lambda x: x + 1
# def compose(*fs):
# return reduce(lambda acc, f: lambda x: acc(f(x)), fs, lambda x: x)
compose = lambda *fs: reduce(lambda acc, f: lambda x: acc(f(x)), fs, lambda x: x)
print reduce(mapper(double)(summer), xrange(5), 0)
print reduce(mapper(double)(maxxer), xrange(5), 0)
print reduce(filterer(even)(summer), xrange(5), 0)
print reduce(filterer(even)(maxxer), xrange(5), 0)
print reduce(filterer(odd)(maxxer), xrange(5), 0)
print reduce(filterer(odd)(summer), xrange(5), 0)
print inc(10)
print double(10)
print 'a', compose(inc, double)(10)
print 'b', compose(double, inc)(10)
# so, in compose(f,g), g goes first, then f.
print reduce(compose(filterer(even), mapper(double))(summer), xrange(5), 0)
print reduce(compose(mapper(double), filterer(even))(summer), xrange(5), 0)
print reduce(compose(mapper(double), mapper(str))(summer), xrange(5), '')
print compose(str, double)(8) # => '16', verified.
print mapper(double)(lambda acc, val: val)(None, 8) # => 16, verified.
print repr(mapper(str)(lambda acc, val: val)(None, 8)) # => '8', verified.
print repr(compose(mapper(double), mapper(str))(lambda acc, val: val)(None, 8))
# => '16', verified. so, the functions seems to go in L to R order.
# what is happening?
wrap = lambda c: lambda s: '{}({})'.format(c, s)
print wrap('f')('x')
print compose(wrap('f'), wrap('g'))('x')
# f(g(x)) : so g goes first,
print compose(lambda s: 'f'+s, lambda s: 'g'+s)('x')
# the identity reducer:
ir = lambda acc, val: val
print reduce(ir, ['x','y'], None) # => x, verified.
print reduce(ir, ['x','y','z'], None) # => z, verified.
print reduce(lambda acc, val: wrap('f')(val), ['x','y'])
print reduce(lambda acc, val: wrap('g')(wrap('f')(val)), ['x','y'])
# the trick is composing transformers.
wrapper = lambda c: lambda reducer: lambda acc, val: reducer(acc, wrap(c)(val))
print reduce(summer, ['a','b','c'], '')
print reduce(wrapper('f')(summer), ['a','b','c'], '')
print reduce(compose(wrapper('f'), wrapper('g'))(summer), ['a','b','c'], '')
print compose(wrapper('f'), wrapper('g'))(summer)('', 'a')
print wrapper('f')(summer)('', 'a') # => f(a)
print compose(wrapper('f'), wrapper('g'))(summer)('', 'a')
print compose(wrapper('f'), wrapper('g'))(ir)('', 'a')
print compose(wrapper('f'), wrapper('g'))(summer)('', 'a')
print wrapper('f')(wrapper('g')(summer))('', 'a')
print wrapper('f')(wrapper('g')(summer))('', 'a')
# wrapper = lambda c: lambda reducer: lambda acc, val: reducer(acc, wrap(c)(val))
print wrapper('f')((lambda reducer: lambda acc, val: reducer(acc, wrap('g')(val)))(summer))('', 'a')
print wrapper('f')(lambda acc, val: summer(acc, wrap('g')(val)))('', 'a')
print wrapper('f')(summer('', wrap('g')('a')))
print summer('', wrap('g')('a'))
# can we work on sets?
print reduce(mapper(lambda x: x+1)(summer), xrange(5), 0)
print reduce(mapper(lambda x: x % 4)(unioner), set(range(10)), set())
print reduce(logger(summer), xrange(5), 0)
#
# F
# turns
# (acc, val) -> acc + val
# into
# (acc, val) -> acc + F(val)
#
# G
# turns
# (acc, val) -> acc + val
# into
# (acc, val) -> acc + G(val)
#
# so compose(F, G): that is,s F(G(_))
#
# turns
# F G
# (acc, val) -> acc + val ------> (acc, val) -> acc + F(val) ------> (acc, val) -> acc + F(G(val))
#
# versus:
#
# F G
# x ------> F(x) ------> G(F(x))
#
# F G
# x -> f(x) ------> x -> f(F(x)) ------> x -> f(F(G(x)))
#
# Another approach:
#
# f takes x to f(x).
# F takes f to a function sending x to f(F(x)); we call that function F(f).
# G takes f to a function sending x to f(G(x)); we call that function G(f).
# So what does G to to F(f)?
# G takes F(f) to a function sending x to F(f)(G(x)).
# But that is f(F(G(x))).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment