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/

Reply via email to