Created
September 19, 2014 18:25
-
-
Save viksit/223dfafe84c54e75deef to your computer and use it in GitHub Desktop.
transducers in python via @ colin_
This file contains 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
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