[Python-ideas] Partial operator (and 'third-party methods' and 'piping') [was Re: Function composition (was no subject)]

Gregory Salvan apieum at gmail.com
Mon May 11 19:46:00 CEST 2015


'is_email_address' is a special tuple which contains functions.
(is_email_address[0] returns is_string)
For help, it's a feature I've not implemented but it's easy to return the
help of each function, plus details as each function has an object
representing it's signature.

For traceback mangling, I don't see what is the problem.
When you call is_email_address(something) it pretty like if you've called:
def is_email_address(value):
    is_string(value)
    has_char('@', value)
    has_user(value)
    has_domain(value)
    return value


2015-05-11 19:08 GMT+02:00 Douglas La Rocca <larocca at abiresearch.com>:

>  Operator overloading (>>) has intuitive readability but in my experience
> it's better have functions remain "ordinary" functions, not class
> instances so you know what to expect regarding the type and so on. The
> other downside is that with (>>) only the functions you wrap can play
> together.
>
>
> Leaving aside the readability concern, the really major problem is that
> your tracebacks are so badly mangled. And if your implementation of
> the composition function uses recursion it gets even worse.
>
>
>  You also lose the benefits of reflection/inspection--for example, with
> the code below, what happens if I call help ?? in ipython on `
> is_email_address`?
>
>
>  ------------------------------
> *From:* Python-ideas <python-ideas-bounces+larocca=
> abiresearch.com at python.org> on behalf of Gregory Salvan <apieum at gmail.com>
> *Sent:* Monday, May 11, 2015 12:13 PM
> *To:* Guido van Rossum
> *Cc:* python-ideas at python.org
> *Subject:* Re: [Python-ideas] Partial operator (and 'third-party methods'
> and 'piping') [was Re: Function composition (was no subject)]
>
>    I don't want to insist and I respect your point of view, I just want
> to give a simplified real life example to show that function composition
> can be less painful than another syntax.
>
>  When validating a lot of data you may want to reuse parts of already
> writen validators. It can also be a mess to test complex data validation.
>  You can reduce this mess and reuse parts of your code by writing atomic
> validators and compose them.
>
>  # sorry for using my own lib, but if I make no mistakes this code
> functions, so...
>
> import re
>  from lawvere import curry # curry is an arrow without type checking,
> inherits composition, mutiple dispatch
>
> user_match =
> re.compile("^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*$").match
> domain_match =
> re.compile("^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$").match
> strict_user_match =
> re.compile("^[a-z0-9][a-z0-9_-]+(?:\.[a-z0-9_-]+)*$").match
>
>  @curry
>  def is_string(value):
>     assert isinstance(value, str), '%s is not a string' %value
>      return value
>
>  @curry
> def apply_until_char(func, char, value):
>      func(value[:value.index(char)])
>     return value
>
>  @curry
>  def apply_from_char(func, char, value):
>      func(value[value.index(char) + 1:])
>      return value
>
> @curry
>  def has_char(char, value):
>     assert value.count(char) == 1
>      return value
>
> @curry
>  def assert_ends_with(text, value):
>      assert value.endswith(text), '%s do not ends with %s' % (value, text)
>      return value
>
> @curry
> def assert_user(user):
>     assert user_match(user) is not None, '%s is not a valid user name' %
> value
>      return user
>
> @curry
> def assert_strict_user(user):
>     assert strict_user_match(user) is not None, '%s is not a valid strict
> user' % value
>      return user
>
> @curry
> def assert_domain(domain):
>     assert domain_match(domain) is not None, '%s is not a valid domain
> name' % value
>      return domain
>
>  # currying (be made with partial)
>  has_user = apply_until_char(assert_user, '@')
>  has_strict_user = apply_until_char(assert_strict_user, '@')
>  has_domain = apply_from_char(assert_domain, '@')
>
>  # composition:
>  is_email_address = is_string >> has_char('@') >> has_user >> has_domain
> is_strict_email_address = is_string >> has_char('@') >> has_strict_user >>
> has_domain
>
>  # we just want org adresses ?
>  is_org_addess = is_email_address >> assert_ends_with('.org')
>
>
>  I found a lot of interest in this syntax, mainly for testing purpose,
> readability and maintenability of code.
>  No matters if I'm a fish out of python waters. :)
>
>
>
>
> 2015-05-11 16:41 GMT+02:00 Guido van Rossum <guido at python.org>:
>
>>  As long as I'm "in charge" the chances of this (or anything like it)
>> being accepted into Python are zero. I get a headache when I try to
>> understand code that uses function composition, and I end up having to
>> laboriously rewrite it using more traditional call notation before I move
>> on to understanding what it actually does. Python is not Haskell, and
>> perhaps more importantly, Python users are not like Haskel users. Either
>> way, what may work out beautifully in Haskell will be like a fish out of
>> water in Python.
>>
>>  I understand that it's fun to try to sole this puzzle, but evolving
>> Python is more than solving puzzles. Enjoy debating the puzzle, but in the
>> end Python will survive without the solution.
>>
>>  --
>> --Guido van Rossum (python.org/~guido)
>>
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150511/2634e3d4/attachment.html>


More information about the Python-ideas mailing list