You are right, of course. Mine does the order wrong. But an 'rcompose()' or 'pipe()' or 'funchain()' is easy enough to put in the right order.
On Aug 19, 2017 3:44 AM, "Steven D'Aprano" <[email protected]> wrote: > On Fri, Aug 18, 2017 at 10:33:40PM -0700, David Mertz wrote: > > > This is pretty easy to write without any syntax changes, just using a > > higher-order function `compose()` (possible implementation at foot). > > Again, I'll assume auto-currying like the map/filter versions of those > > functions in toolz, as Steven does: > [...] > > > result = compose(map(str.strip), > > filter(lambda s: not startswith('#'), > > sorted, > > collapse, > > extract_dates, > > map(date_to_seconds), > > min > > )(myfile.readlines()) > > A ~~slight~~ major nit: given the implementation of compose you quote > below, this applies the functions in the wrong order. min() is called > first, and map(str.strip) last. > > But apart from being completely wrong *wink* that's not too bad :-) > > Now we start bike-shedding the aethetics of what looks better > and reads more nicely. Your version is pretty good, except: > > 1) The order of function composition is backwards to that normally > expected (more on this below); > > 2) there's that unfortunate call to "compose" which isn't actually part > of the algorithm, its just scaffolding to make it work; > > 3) the data being operated on still at the far end of the chain, instead > of the start; > > 4) and I believe that teaching a chain of function calls is easier than > teaching higher order function composition. Much easier. > > > The standard mathematical definition of function composition operates > left to right: > > (f∘g∘h)(x) = f(g(h(x)) > > http://mathworld.wolfram.com/Composition.html > > And that's precisely what your implementation does. Given your > implementation quoted below: > > py> def add_one(x): return x + 1 > ... > py> def double(x): return 2*x > ... > py> def take_one(x): return x - 1 > ... > py> > py> compose(add_one, > ... double, > ... take_one)(10) > 19 > py> > py> add_one(double(take_one(10))) > 19 > > which is the mathematically expected behaviour. But for chaining, we > want the operations in the opposite order: > > 10 -> add_one -> double -> take_one > > which is equivalent to: > > take_one(double(add_one(10)) > > > So to use composition for chaining, we need: > > > - a non-standard implementation of chaining, which operates in the > reverse to what mathematicians and functional programmers expect; > > - AND remember to use this rcompose() instead of compose() > > - stick to the standard compose(), but put the functions in the > reverse order to what we want; > > - or use the standard compose, but use even more scaffolding to > make it work: > > result = compose(*reversed( > ( map(str.strip), > filter(lambda s: not startswith('#')), > sorted, > collapse, > extract_dates, > map(date_to_seconds), > min > )))(myfile.readlines()) > > > > def compose(*funcs): > > """Return a new function s.t. > > compose(f,g,...)(x) == f(g(...(x))) > > """ > > def inner(data, funcs=funcs): > > result = data > > for f in reversed(funcs): > > result = f(result) > > return result > > return inner > > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > [email protected] > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ Python-ideas mailing list [email protected] https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
