[Python-ideas] Re: Function composition

2020-05-25 Thread Joao S. O. Bueno
Really,
I don't think new syntax is needed for that, as it is trivially resolved
by a function call

(I would type an example but Ricky's answer covers it)

Moreover, such a callable, or other helper-callables
can trivially enable ways of connecting the piped
values through specific (positional/named) parameters
in the next calls - allowing a whole Graph of functions
to be composed.

(And it is so easy to do and flexible extendable, I can't see a place for
that
in the stdlib)



On Mon, 25 May 2020 at 00:11, Ricky Teachey  wrote:

> Here's another whacky idea: how about adding a so-called FuncSeq to the
> collections library for composing functions?
>
> Since FuncSeq is (obviously) a sequence, that might help with the
> intuition of the function application order. The idea is the function
> application order is the same as the iteration order of the sequence:
>
> from collections import FuncSeq
>
> fun_seq = FuncSeq([str, len])
> fun_seq(789)  # 3
> fun_seq[::-1]("789")  # '3'
>
> ---
> Ricky.
>
> "I've never met a Kentucky man who wasn't either thinking about going home
> or actually going home." - Happy Chandler
>
>
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/IFTDGP3JLYFI3YZZDPFKIRA7QBV73W2N/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DTFJQMWUT2SO276JLR3JY5XCZRNSKAUU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Ricky Teachey
Here's another whacky idea: how about adding a so-called FuncSeq to the
collections library for composing functions?

Since FuncSeq is (obviously) a sequence, that might help with the intuition
of the function application order. The idea is the function application
order is the same as the iteration order of the sequence:

from collections import FuncSeq

fun_seq = FuncSeq([str, len])
fun_seq(789)  # 3
fun_seq[::-1]("789")  # '3'

---
Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home
or actually going home." - Happy Chandler
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/IFTDGP3JLYFI3YZZDPFKIRA7QBV73W2N/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Cameron Simpson

On 24May2020 19:28, David Mertz  wrote:

On Sun, May 24, 2020 at 6:56 PM Steven D'Aprano  wrote:


> I use bash a lot, and writing something like this is common:
> cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c

And today's "Useless Use Of cat Award" goes to... :-)

sort data | ...

(What is it specifically about cat that is so attractive? I almost
certainly would have done exactly what you did, even knowing that sort
will take a file argument.)



This is probably going afield since it is a bash thing, not a Python
thing.  But I can actually answer this quite specifically.

When I write a pipeline like that, I usually do not do it in one pass.  I
write a couple of the stages, look at what I have, and then add some more
stages until I get it right.  Many of the commands in the pipeline can take
a file argument (not just sort, also cut, also grep, also uniq...
everything I used in the example).


People forget that redirections may appear anywhere rather than just at 
the end of the command:


   output

But I take your point on incremental build-the-pipeline, I do that a 
lot.


Cheers,
Cameron Simpson 
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/26XKIQ6VS4ALVT52PL4ON33SUNNX33WR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Greg Ewing

On 25/05/20 3:27 am, Ram Rachum wrote:
Speaking of evil, another evil idea would be to write code that modifies 
the ast and changes @ between functions to call a compose function instead.


How do you tell just from the ast whether a particular @ is
between functions?

--
Greg
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/MBFTJF2HLMW2BDS5LJWD4OV7BFF4TLT3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Dan Sommers


On Sunday, May 24, 2020, at 18:58 -0400, Chris Angelico wrote:

>  Maybe it's function call syntax that is the weird one. It might be
> familiar to us, but maybe it's the one that's actually causing the
> weirdness. Suppose we wrote the function last:
> 
> (data)sort
> 
> Now it's basically become a pipeline. And yet this syntax looks so
> utterly bizarre that none of us would accept it...

Get rid of the parentheses.  We'll call it "postfix notation."

Ever written any postscript code?  Or forth?  ;-)
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DLXONAAC4AQVXSN7TNQ6NR7UQ533GTX5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread David Mertz
On Sun, May 24, 2020, 9:03 PM Rob Cliffe via Python-ideas

> In fact it's *more* intuitive than what we do now (evaluation is strictly
> left-to-right),  as can be seen with composed functions:
>
>  ((path)str)len


Forth was created in 1970. The idea isn't brand new.

C is two years newer (1972). But Algol is 12 years older (1958).

Most languages of the last 30 years seem to be influenced most by C, or at
least the Algol tradition for basic syntax. That doesn't mean it's better,
but it won out for whatever reason.

Smalltalk (1972) is interestingly different from either the Forth or Algol
style. But closer to Forth.

Fwiw, I don't think I'd have much difficulty adjusting to the postfix
calling style, but Python isn't going to do that, even in version 17.3 in
2100.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/PP3C5TWPBSWA5ZY2LD5ABGIO3MI66U7O/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Rob Cliffe via Python-ideas

On 24/05/2020 23:58, Chris Angelico wrote:

Maybe it's function call syntax that is the weird one. It might be
familiar to us, but maybe it's the one that's actually causing the
weirdness. Suppose we wrote the function last:

(data)sort

Now it's basically become a pipeline. And yet this syntax looks so
utterly bizarre that none of us would accept it...

Well ...

ChrisA

Good outside-the-box thinking, Chris.
The kind of spelling-out-the-obvious and 
looking-at-the-familiar-from-a-new-viewpoint

to come up with a revolutionary idea that is characteristic of genius -
Darwin, Einstein et al.  (Was it entirely your own idea? :-))
I'm sure one could get used to this syntax.
In fact it's *more* intuitive than what we do now (evaluation is 
strictly left-to-right),

 as can be seen with composed functions:

    ((path)str)len
# First does something with 'path' and 'str', then does something with 
the result and `len'.

# Not: first does something with `len' and ... what?

Jesus, why is the whole world not using it already?
Maybe for the same reason the world still uses QWERTY keyboards.
Maybe that's what programmers (well, the smart ones:-))  in 2100 using 
Python 42 will use.


Hell, it's currently illegal syntax.  Maybe it could be introduced soon 
(would the new parser help? :-)) ,
in the hope that people will gradually fall out of the old usage 
`sort(data)`,
so that eventually it can be deprecated and finally dropped (by 2100 or 
thereabouts).

(Guido, are you listening?)
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HYY3ZA6AYUEZYMXKL3RSRTLFBDKGAO6E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Michael Mitchell
 JavaScript has an early proposal for this use-case:
https://github.com/tc39/proposal-partial-application#pipeline-and-partial-application
where "cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c" could
be represented as:
  data
|> sort
|> cut(?, delimeter=";", fields=6)
|> grep(?, "^foo")
|> sort(?, reverse=True)
|> uniq(?, count=True)

A very similar operator already exists for Hack which has served to clean
up a lot of code at Facebook:
https://docs.hhvm.com/hack/expressions-and-operators/pipe

( fun fact: I was one of the people who asked for __matmul__ back in the
day, but now I prefer the pipeline operator as it's not restricted to unary
functions and is, IMHO, more readable
https://mail.python.org/archives/list/python-ideas@python.org/message/I4DXFR4P5KAMHDL4MRAM43QCUMW4MIJY
)

On Sun, May 24, 2020 at 7:33 PM David Mertz  wrote:

> On Sun, May 24, 2020 at 6:56 PM Steven D'Aprano 
> wrote:
>
>> > I use bash a lot, and writing something like this is common:
>> > cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c
>>
>> And today's "Useless Use Of cat Award" goes to... :-)
>>
>> sort data | ...
>>
>> (What is it specifically about cat that is so attractive? I almost
>> certainly would have done exactly what you did, even knowing that sort
>> will take a file argument.)
>>
>
> This is probably going afield since it is a bash thing, not a Python
> thing.  But I can actually answer this quite specifically.
>
> When I write a pipeline like that, I usually do not do it in one pass.  I
> write a couple of the stages, look at what I have, and then add some more
> stages until I get it right.  Many of the commands in the pipeline can take
> a file argument (not just sort, also cut, also grep, also uniq...
> everything I used in the example).
>
> But I find fairly often that I need to add a step BEFORE what I initially
> thought was first processing step.  And then I have to remove the filename
> as an argument of that no-longer-first step.  Rinse and repeat.  With `cat`
> I know it does nothing, and I won't have to change it later (well, OK,
> sometimes I want -n or -s).  So it is a completely generic "data" object
> ... sort of like how I would write "fluent programming" starting with a
> Pandas DataFrame, for example, and calling chains of methods..
>
> --
> The dead increasingly dominate and strangle both the living and the
> not-yet born.  Vampiric capital and undead corporate persons abuse
> the lives and control the thoughts of homo faber. Ideas, once born,
> become abortifacients against new conceptions.
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/7DRNTPAWCU5SA666E6ZLEXZQVUYCS7VN/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/VL5KWUV5TFTDS5VWTKP2MBL47GP4IU75/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread David Mertz
On Sun, May 24, 2020 at 6:56 PM Steven D'Aprano  wrote:

> > I use bash a lot, and writing something like this is common:
> > cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c
>
> And today's "Useless Use Of cat Award" goes to... :-)
>
> sort data | ...
>
> (What is it specifically about cat that is so attractive? I almost
> certainly would have done exactly what you did, even knowing that sort
> will take a file argument.)
>

This is probably going afield since it is a bash thing, not a Python
thing.  But I can actually answer this quite specifically.

When I write a pipeline like that, I usually do not do it in one pass.  I
write a couple of the stages, look at what I have, and then add some more
stages until I get it right.  Many of the commands in the pipeline can take
a file argument (not just sort, also cut, also grep, also uniq...
everything I used in the example).

But I find fairly often that I need to add a step BEFORE what I initially
thought was first processing step.  And then I have to remove the filename
as an argument of that no-longer-first step.  Rinse and repeat.  With `cat`
I know it does nothing, and I won't have to change it later (well, OK,
sometimes I want -n or -s).  So it is a completely generic "data" object
... sort of like how I would write "fluent programming" starting with a
Pandas DataFrame, for example, and calling chains of methods..

-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/7DRNTPAWCU5SA666E6ZLEXZQVUYCS7VN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Chris Angelico
On Mon, May 25, 2020 at 8:54 AM Steven D'Aprano  wrote:
>
> On Sun, May 24, 2020 at 06:31:46PM -0400, David Mertz wrote:
>
> > I think one thing that pulls in different directions is that both
> > composition and piping are useful, and do something closely related.  But
> > in one the data "goes" forward and in the other the data "goes backward."
>
> The same rule applies to function application though.
>
> > I use bash a lot, and writing something like this is common:
> >
> > cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c
>
> And today's "Useless Use Of cat Award" goes to... :-)
>
> sort data | ...
>
> (What is it specifically about cat that is so attractive? I almost
> certainly would have done exactly what you did, even knowing that sort
> will take a file argument.)

https://http.cat/304 )

> Compared to the regular old function call syntax:
>
> uniq(sort(grep(cut(sort(data)
>
> (ignoring extra arguments) where the data still moves right to left.
>
> On the third hand, even if your language doesn't have pipes, it may have
> methods:
>
> data.sort().cut().grep().sort().uniq()
>
> which now moves left to right again.
>

Maybe it's function call syntax that is the weird one. It might be
familiar to us, but maybe it's the one that's actually causing the
weirdness. Suppose we wrote the function last:

(data)sort

Now it's basically become a pipeline. And yet this syntax looks so
utterly bizarre that none of us would accept it...

ChrisA
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/PP4UPFFHX55V7U2FJDCRFSCZQ2XTHJ2C/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Steven D'Aprano
On Sun, May 24, 2020 at 06:31:46PM -0400, David Mertz wrote:

> I think one thing that pulls in different directions is that both
> composition and piping are useful, and do something closely related.  But
> in one the data "goes" forward and in the other the data "goes backward."

The same rule applies to function application though.

> I use bash a lot, and writing something like this is common:
> 
> cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c

And today's "Useless Use Of cat Award" goes to... :-)

sort data | ...

(What is it specifically about cat that is so attractive? I almost 
certainly would have done exactly what you did, even knowing that sort 
will take a file argument.)


> My data is moving left to right through the operations.  In contrast, I
> might write in some hypothetical programming language:
> 
> myfilter = uniq[count] ∘ sort[reverse] ∘ grep[^foo] ∘ cut[;,f6] ∘ sort
> result = myfilter(data)

Compared to the regular old function call syntax:

uniq(sort(grep(cut(sort(data)

(ignoring extra arguments) where the data still moves right to left.

On the third hand, even if your language doesn't have pipes, it may have 
methods:

data.sort().cut().grep().sort().uniq()

which now moves left to right again.

-- 
Steven
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/QNW2ARA4VEYE4KAQ35OR53JKTKVYDPBF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread David Mertz
Tiimmy:

> Best I know, f@g applies g first in every language that implements a
>>
> composition operator, and in mathematics. While that may be arbitrary,
>> it's easy to remember:  (f@g)(x)  "looks a heck of a lot more like"
>> f(g(x)) than g(f(x))
>>
>
On Sun, May 24, 2020 at 5:39 PM Guido van Rossum  wrote:

> Dang, you're right. It works as you'd expect without overthinking it. :-)
>

I think one thing that pulls in different directions is that both
composition and piping are useful, and do something closely related.  But
in one the data "goes" forward and in the other the data "goes backward."

I use bash a lot, and writing something like this is common:

cat data | sort | cut -d; -f6 | grep ^foo | sort -r | uniq -c

My data is moving left to right through the operations.  In contrast, I
might write in some hypothetical programming language:

myfilter = uniq[count] ∘ sort[reverse] ∘ grep[^foo] ∘ cut[;,f6] ∘ sort
result = myfilter(data)

(In my just-now-invented PL, the square brackets are some kind of partial
application operators)

Here my data is moving right to left within the composition.  Haskell
spells pipes approximately `>>`, F# as `|>`, R as `%>%`, and so on.  But
some of the same languages also have composition (point-free style) that
reverses the order of operations (using different symbols).

-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/VBFQU6IBJ5RTF4TLHTS45BAZC6CEATZ6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Alex Hall
On Sun, May 24, 2020 at 11:17 PM Tim Peters  wrote:

> [Guido]
> >> I’ve never been able to remember whether (f@g)(x) means f(g(x)) or
> g(f(x)). That pretty much kills the idea for me.
>
> [David Mertz]
> > Well, it means whichever one the designers decide it should mean. But
> obviously it's a thing to remember,
> > and one that could sensibly go the other way.
> >
> > On the other hand, when I showed an example using filter() a couple days
> ago, I had to try it to remember whether
> > the predicate or the iterable came first. Lots of such decisions are
> pretty arbitrary.
>
> Best I know, f@g applies g first in every language that implements a
> composition operator, and in mathematics. While that may be arbitrary,
> it's easy to remember:  (f@g)(x)  "looks a heck of a lot more like"
> f(g(x)) than g(f(x)) because the former leaves the identifiers in the
> same order.
>

I personally find it easy to remember, but I can imagine (perhaps
incorrectly) how others may find it difficult. There's a 'wrong' rule
that's equally easy to remember: f@g means call f then call g. In fact,
when you think of it like that, you might not even notice that this means
g(f(x)). So even if you know that f@g means f(g(x)), you can still mess
this up by not thinking it through.

This is similar to when you have a list of decorators. Lots of people
expect them to be called top to bottom (
https://stackoverflow.com/questions/27342149/decorator-execution-order) and
it's not easy to make the real order feel more intuitive.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/VSZ5XIVRO62T5A5CG7Q22JN66GEZ5B45/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Guido van Rossum
Dang, you're right. It works as you'd expect without overthinking it. :-)

I guess what has always (seriously, since my undergrad years studying
math!) confused me is that somehow when this function is introduced
 they say (g*f)(x) =
g(f(x)). The professor starts by showing f(x), and then shows how you can
apply g() to the result, and lo, you have defined g*f.

(I'm sorry, I refuse to learn how to type the symbol they actually use. :-)

On Sun, May 24, 2020 at 2:17 PM Tim Peters  wrote:

> [Guido]
> >> I’ve never been able to remember whether (f@g)(x) means f(g(x)) or
> g(f(x)). That pretty much kills the idea for me.
>
> [David Mertz]
> > Well, it means whichever one the designers decide it should mean. But
> obviously it's a thing to remember,
> > and one that could sensibly go the other way.
> >
> > On the other hand, when I showed an example using filter() a couple days
> ago, I had to try it to remember whether
> > the predicate or the iterable came first. Lots of such decisions are
> pretty arbitrary.
>
> Best I know, f@g applies g first in every language that implements a
> composition operator, and in mathematics. While that may be arbitrary,
> it's easy to remember:  (f@g)(x)  "looks a heck of a lot more like"
> f(g(x)) than g(f(x)) because the former leaves the identifiers in the
> same order.
>


-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/IH4FDKQEBPFGOW7VKDPVLUTJQBTNPMOO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread David Mertz
On Sun, May 24, 2020, 5:11 PM Alex Hall

> But when you *read* a call to filter(), it's generally pretty obvious
> which argument is which, even if you don't remember the signature. You just
> need to see which one's callable or which one's iterable (few things are
> both). You can probably guess just from the variable names. If you read `f@g`,
> you can only guess if one of `f(g(x))` or `g(f(x))` is nonsense, which I
> think is typically less obvious.
>

I definitely agree. My way of remembering which way filter goes was to try
the wrong one in a shell and get an exception.

In contrast, quite likely both f(g(h(x))) and h(g(f(x))) produce a value,
but only one is the one I want. If x is  string, or a list, or a number, or
a NumPy array, most functions I'd call return something of the same type.
Mutations are usually not order independent.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/JKW6HJPPIUSS4IHBTWUGLL4HMMFLOM6T/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Tim Peters
[Guido]
>> I’ve never been able to remember whether (f@g)(x) means f(g(x)) or g(f(x)). 
>> That pretty much kills the idea for me.

[David Mertz]
> Well, it means whichever one the designers decide it should mean. But 
> obviously it's a thing to remember,
> and one that could sensibly go the other way.
>
> On the other hand, when I showed an example using filter() a couple days ago, 
> I had to try it to remember whether
> the predicate or the iterable came first. Lots of such decisions are pretty 
> arbitrary.

Best I know, f@g applies g first in every language that implements a
composition operator, and in mathematics. While that may be arbitrary,
it's easy to remember:  (f@g)(x)  "looks a heck of a lot more like"
f(g(x)) than g(f(x)) because the former leaves the identifiers in the
same order.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/6C337WG4GVPBLT2V6VZ3IVMX42BOJBRW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Alex Hall
On Sun, May 24, 2020 at 10:53 PM David Mertz  wrote:

> On Sun, May 24, 2020, 3:43 PM Guido van Rossum  wrote:
>
>> I’ve never been able to remember whether (f@g)(x) means f(g(x)) or
>> g(f(x)). That pretty much kills the idea for me.
>>
>
> Well, it means whichever one the designers decide it should mean. But
> obviously it's a thing to remember, and one that could sensibly go the
> other way.
>
> On the other hand, when I showed an example using filter() a couple days
> ago, I had to try it to remember whether the predicate or the iterable came
> first. Lots of such decisions are pretty arbitrary.
>

But when you *read* a call to filter(), it's generally pretty obvious which
argument is which, even if you don't remember the signature. You just need
to see which one's callable or which one's iterable (few things are both).
You can probably guess just from the variable names. If you read `f@g`, you
can only guess if one of `f(g(x))` or `g(f(x))` is nonsense, which I think
is typically less obvious. Taking the `len@str` example, `str(len(path))`
is a sensible expression, it's just a terrible sort key, and having to
think that far sucks for readability.

Also in the paths example, if you remember wrong and write the equivalent
of `sorted(paths, key=lambda path: str(len(path)))`, you get a list in
nonsense order which may be confusing to debug. If you get the order wrong
in `filter()`, you should eventually get an error like `TypeError: 'list'
object is not callable`.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/IAXF7TUSK6ANFPZ26USCDVPQE4BFMD4P/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread David Mertz
On Sun, May 24, 2020, 3:43 PM Guido van Rossum  wrote:

> I’ve never been able to remember whether (f@g)(x) means f(g(x)) or
> g(f(x)). That pretty much kills the idea for me.
>

Well, it means whichever one the designers decide it should mean. But
obviously it's a thing to remember, and one that could sensibly go the
other way.

On the other hand, when I showed an example using filter() a couple days
ago, I had to try it to remember whether the predicate or the iterable came
first. Lots of such decisions are pretty arbitrary.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/FWU4J4QKH3WDHQ6FZLMOXXQ35MA5MGU6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Guido van Rossum
I’ve never been able to remember whether (f@g)(x) means f(g(x)) or g(f(x)).
That pretty much kills the idea for me.

On Sun, May 24, 2020 at 11:10 Alex Hall  wrote:

> On Sun, May 24, 2020 at 6:56 PM David Mertz  wrote:
>
>> On Sun, May 24, 2020 at 11:21 AM Steven D'Aprano 
>> wrote:
>>
>>> > But how would you go about getting a .__matmul__ attribute onto all
>>> > functions. For ones you write yourselves, you could decorate them at
>>> > definition. What about all the other functions though.
>>>
>>> As a functional programming fan, you might not know about this, but we
>>> object oriented programming people have this concept called
>>> "inheritance" where we would add the attribute to FunctionType once, and
>>> just like magic every function would support it!
>>>
>>
>> I think I heard of that inheritance thing somewhere! :-)
>>
>> My thought is really that there's no way we're going to get .__matmul__
>> added (with the meaning "compose") to FunctionType.  So I was thinking
>> about what one could do with a separate module.  I.e. something that could
>> live on PyPI... before, perhaps someday, being added to standard library.
>>
>> Is there an evil way to monkey patch FunctionType? I.e. without actually
>> recompiling a fork of the interpreter.  Alex' forbiddenfruit.curse is
>> pretty cool looking.  But it does require explicitly cursing each
>> individual function that might be composed.
>>
>
> forbiddenfruit patches the type, look again. I used a loop because there
> isn't just one FunctionType: `type(compose) != type(len)`.
>
>
>> Alex Hall:
>>
>>> But seriously, I don't see that much point to this idea. It's just
>>> slightly more concise while not being particularly readable or beginner
>>> friendly.
>>>
>>> sorted(paths, key=len @ str)
>>> sorted(paths, key=lambda p: len(str(p)))
>>>
>>
>> I think once you compose three or more functions, lambda starts to look
>> pretty bad.
>>
>
> It does? How? It sounds like the problem isn't the syntax for lambda, but
> just function composition in general, maybe because of too many
> parentheses. Maybe you'd like to change:
>
> foo = bar(len(str(path)))
>
> into
>
> foo = (bar @ len @ str)(path)
>
> In any case, it's rare to be able to simply compose three unary functions,
> e.g. `sorted(paths, key=bar @ len @ str)`. Usually you need to do something
> slightly more complicated, e.g. a second argument somewhere, and if you
> throw in functools.partial I think that's easily worse.
>
>
>> This is only slightly mitigated by one of those proposals for "a more
>> concise lambda" that occur intermittently. And if you actually save a
>> composed function under a meaningful name for later use, that much more so.
>>
>
> Why is:
>
> my_op = bar @ len @ str
>
> even more of an improvement over:
>
> my_op = lambda p: bar(len(str(p)))
>
> than @ is an improvement in the previous examples? If the answer is that
> you're not supposed to assign lambdas, I think the same logic should
> dictate not assigning compositions.
>
> In fact, the reason to not assign lambdas is for better tracebacks,
> and now that I think of it, function composition would completely destroy
> tracebacks. For example:
>
> ```
> for function in [
> lambda p: str(len(p)),
> str @ len,
> ]:
> try:
> function(3)
> except:
> traceback.print_exc()
>
> ```
>
> Output:
>
> ```
> Traceback (most recent call last):
>   File "main.py", line 15, in 
> function(3)
>   File "main.py", line 11, in 
> lambda p: str(len(p)),
> TypeError: object of type 'int' has no len()
> Traceback (most recent call last):
>   File "main.py", line 15, in 
> function(3)
>   File "main.py", line 5, in 
> return lambda *args, **kwargs: self(other(*args, **kwargs))
> TypeError: object of type 'int' has no len()
> ```
>
> https://repl.it/@alexmojaki/LeanEnergeticPublisher-1
>
> So based on that I'm strongly against this kind of proposal without
> syntactic support.
>
> I've been playing more lately with R Tidyverse.  It's pipe with currying
>> of first argument is actually really nice.  The pipe operator is god-awful
>> ugly.  But other than that it works nicely.  For example:
>>
>> iris %>%  group_by(Species) %>%  summarize_if(is.numeric, mean) %>%  
>> ungroup() %>%  gather(measure, value, -Species) %>%  arrange(value)
>>
>>
>> It's not abstract composition since it always starts with a concrete
>> object the several operations work on.  But it is some of the same feel.
>>
>
> https://github.com/0101/pipetools
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/JURJ5YTZ2ESEBVZYNNJ4RDSCEMH5RPB3/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
Python-ideas maili

[Python-ideas] Re: Function composition

2020-05-24 Thread Alex Hall
On Sun, May 24, 2020 at 6:56 PM David Mertz  wrote:

> On Sun, May 24, 2020 at 11:21 AM Steven D'Aprano 
> wrote:
>
>> > But how would you go about getting a .__matmul__ attribute onto all
>> > functions. For ones you write yourselves, you could decorate them at
>> > definition. What about all the other functions though.
>>
>> As a functional programming fan, you might not know about this, but we
>> object oriented programming people have this concept called
>> "inheritance" where we would add the attribute to FunctionType once, and
>> just like magic every function would support it!
>>
>
> I think I heard of that inheritance thing somewhere! :-)
>
> My thought is really that there's no way we're going to get .__matmul__
> added (with the meaning "compose") to FunctionType.  So I was thinking
> about what one could do with a separate module.  I.e. something that could
> live on PyPI... before, perhaps someday, being added to standard library.
>
> Is there an evil way to monkey patch FunctionType? I.e. without actually
> recompiling a fork of the interpreter.  Alex' forbiddenfruit.curse is
> pretty cool looking.  But it does require explicitly cursing each
> individual function that might be composed.
>

forbiddenfruit patches the type, look again. I used a loop because there
isn't just one FunctionType: `type(compose) != type(len)`.


> Alex Hall:
>
>> But seriously, I don't see that much point to this idea. It's just
>> slightly more concise while not being particularly readable or beginner
>> friendly.
>>
>> sorted(paths, key=len @ str)
>> sorted(paths, key=lambda p: len(str(p)))
>>
>
> I think once you compose three or more functions, lambda starts to look
> pretty bad.
>

It does? How? It sounds like the problem isn't the syntax for lambda, but
just function composition in general, maybe because of too many
parentheses. Maybe you'd like to change:

foo = bar(len(str(path)))

into

foo = (bar @ len @ str)(path)

In any case, it's rare to be able to simply compose three unary functions,
e.g. `sorted(paths, key=bar @ len @ str)`. Usually you need to do something
slightly more complicated, e.g. a second argument somewhere, and if you
throw in functools.partial I think that's easily worse.


> This is only slightly mitigated by one of those proposals for "a more
> concise lambda" that occur intermittently. And if you actually save a
> composed function under a meaningful name for later use, that much more so.
>

Why is:

my_op = bar @ len @ str

even more of an improvement over:

my_op = lambda p: bar(len(str(p)))

than @ is an improvement in the previous examples? If the answer is that
you're not supposed to assign lambdas, I think the same logic should
dictate not assigning compositions.

In fact, the reason to not assign lambdas is for better tracebacks, and now
that I think of it, function composition would completely destroy
tracebacks. For example:

```
for function in [
lambda p: str(len(p)),
str @ len,
]:
try:
function(3)
except:
traceback.print_exc()

```

Output:

```
Traceback (most recent call last):
  File "main.py", line 15, in 
function(3)
  File "main.py", line 11, in 
lambda p: str(len(p)),
TypeError: object of type 'int' has no len()
Traceback (most recent call last):
  File "main.py", line 15, in 
function(3)
  File "main.py", line 5, in 
return lambda *args, **kwargs: self(other(*args, **kwargs))
TypeError: object of type 'int' has no len()
```

https://repl.it/@alexmojaki/LeanEnergeticPublisher-1

So based on that I'm strongly against this kind of proposal without
syntactic support.

I've been playing more lately with R Tidyverse.  It's pipe with currying of
> first argument is actually really nice.  The pipe operator is god-awful
> ugly.  But other than that it works nicely.  For example:
>
> iris %>%  group_by(Species) %>%  summarize_if(is.numeric, mean) %>%  
> ungroup() %>%  gather(measure, value, -Species) %>%  arrange(value)
>
>
> It's not abstract composition since it always starts with a concrete
> object the several operations work on.  But it is some of the same feel.
>

https://github.com/0101/pipetools
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/JURJ5YTZ2ESEBVZYNNJ4RDSCEMH5RPB3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread David Mertz
On Sun, May 24, 2020 at 11:21 AM Steven D'Aprano 
wrote:

> > But how would you go about getting a .__matmul__ attribute onto all
> > functions. For ones you write yourselves, you could decorate them at
> > definition. What about all the other functions though.
>
> As a functional programming fan, you might not know about this, but we
> object oriented programming people have this concept called
> "inheritance" where we would add the attribute to FunctionType once, and
> just like magic every function would support it!
>

I think I heard of that inheritance thing somewhere! :-)

My thought is really that there's no way we're going to get .__matmul__
added (with the meaning "compose") to FunctionType.  So I was thinking
about what one could do with a separate module.  I.e. something that could
live on PyPI... before, perhaps someday, being added to standard library.

Is there an evil way to monkey patch FunctionType? I.e. without actually
recompiling a fork of the interpreter.  Alex' forbiddenfruit.curse is
pretty cool looking.  But it does require explicitly cursing each
individual function that might be composed.

Alex Hall:

> But seriously, I don't see that much point to this idea. It's just
> slightly more concise while not being particularly readable or beginner
> friendly.
>
> sorted(paths, key=len @ str)
> sorted(paths, key=lambda p: len(str(p)))
>

I think once you compose three or more functions, lambda starts to look
pretty bad.  This is only slightly mitigated by one of those proposals for
"a more concise lambda" that occur intermittently. And if you actually save
a composed function under a meaningful name for later use, that much more
so.  Of course, I'm really not all that bothered by `my_op = compose(fun1,
fun2, fun3, fun4)`.  The @ might be cool, but writing my own HoF compose()
isn't hard.

I've been playing more lately with R Tidyverse.  It's pipe with currying of
first argument is actually really nice.  The pipe operator is god-awful
ugly.  But other than that it works nicely.  For example:

iris %>%  group_by(Species) %>%  summarize_if(is.numeric, mean) %>%
ungroup() %>%  gather(measure, value, -Species) %>%  arrange(value)


It's not abstract composition since it always starts with a concrete object
the several operations work on.  But it is some of the same feel.

-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/X5N4UWZJYWMFCRSXLJW36THUHAJSOHXI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Alex Hall
On Sun, May 24, 2020 at 4:55 PM David Mertz  wrote:

> Changed subject line. This is far from original topic.
>
> On Sun, May 24, 2020, 9:35 AM Ram Rachum  wrote:
>
>> What's wrong with using @? If I understand correctly, it's used for
>> matrix multiplication, which is far enough from function composition to
>> avoid confusion. And it's slightly similar visually to a circle.
>>
>
> I like @. Function composition is kinda-sorta enough like for product that
> I can even make sense of the same operator.
>
> But how would you go about getting a .__matmul__ attribute onto all
> functions.
>

That's easy, especially when everyone is talking about evil.

```
from forbiddenfruit import curse

def compose(self, other):
return lambda *args, **kwargs: self(other (*args, **kwargs))

for func in [compose, len]:
curse(type(func), "__matmul__", compose)

assert (len @ str)(789) == 3

```

https://repl.it/@alexmojaki/LeanEnergeticPublisher#main.py

But seriously, I don't see that much point to this idea. It's just slightly
more concise while not being particularly readable or beginner friendly.

```
sorted(paths, key=len @ str)
sorted(paths, key=lambda p: len(str(p)))
```

I think the problem is just that lambda isn't the nicest syntax, and we'd
like something more concise, e.g.

```
sorted(paths, key=:len(str($)))
```

which would be more generally useful. But I know this kind of thing has
been discussed to death.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/LQX2GXNTTKHDM7MPNKXKLHPN7QECKZJA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Ram Rachum
Speaking of evil, another evil idea would be to write code that modifies
the ast and changes @ between functions to call a compose function instead.

On Sun, May 24, 2020, 18:21 Steven D'Aprano  wrote:

> On Sun, May 24, 2020 at 10:49:45AM -0400, David Mertz wrote:
>
> > But how would you go about getting a .__matmul__ attribute onto all
> > functions. For ones you write yourselves, you could decorate them at
> > definition. What about all the other functions though.
>
> As a functional programming fan, you might not know about this, but we
> object oriented programming people have this concept called
> "inheritance" where we would add the attribute to FunctionType once, and
> just like magic every function would support it!
>
> *wink*
>
> Steven
> (the evil twin)
>
> P.S. sadly, operator dunders are looked up on the class, not the
> instance, so adding a `__matmul__` method to individual functions
> doesn't help. It would have to be done at the class.
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/7SZBKY5JJBQ3SOQIUQO2NUKKCS3BRF4J/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/P4RSSFL2TNNWCQMPRDJALEZYTHCOOIJL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Function composition

2020-05-24 Thread Steven D'Aprano
On Sun, May 24, 2020 at 10:49:45AM -0400, David Mertz wrote:

> But how would you go about getting a .__matmul__ attribute onto all
> functions. For ones you write yourselves, you could decorate them at
> definition. What about all the other functions though.

As a functional programming fan, you might not know about this, but we 
object oriented programming people have this concept called 
"inheritance" where we would add the attribute to FunctionType once, and 
just like magic every function would support it!

*wink*

Steven
(the evil twin)

P.S. sadly, operator dunders are looked up on the class, not the 
instance, so adding a `__matmul__` method to individual functions 
doesn't help. It would have to be done at the class.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/7SZBKY5JJBQ3SOQIUQO2NUKKCS3BRF4J/
Code of Conduct: http://python.org/psf/codeofconduct/