Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More user-friendly lambda functions #4

Open
smarie opened this issue Nov 20, 2019 · 2 comments
Open

More user-friendly lambda functions #4

smarie opened this issue Nov 20, 2019 · 2 comments

Comments

@smarie
Copy link
Owner

smarie commented Nov 20, 2019

Our original need was to raise user-friendly errors in case of failed validation. It is very frequent that a validation operation just consists in a few operations, and it is therefore quite convenient to express it as a lambda function. There are two main issues then:

  • it is not easy to retrieve the lambda expression itself so as to display it in a message such as "validation failed: x > 2 returned False".
  • the lambda <vars>: prefix is sometimes a bit cumbersome. Being able to import or create special input symbols so that lambda is implicit would make the code more readable.

For this reason I created mini-lambda but it has some major limitations (one input only, and some python operators can not be used because the corresponding magic method has too much constraints).

Maybe we could propose a PEP about

  • at least string representation for lambda functions (quite easy to specify and implement I guess)
  • and maybe, but this is much harder, about new symbols that could be used to create "implicit lambdas"... Thoughts ?

See also this stackoverflow post

@smarie smarie changed the title [mini-lambda] more user-friendly lambda functions More user-friendly lambda functions Sep 7, 2020
@plammens
Copy link

plammens commented Sep 18, 2020

I like the idea of adding a str representation of lambdas that includes the source code. Some concerns (perhaps not really concerning, but just a couple of things that came to mind):

  • The increased memory usage.
  • If the string representation is just the source of the lambda as-is, how can we distinguish between global names, local names (from the lambda's closure), and the actual lambda parameters? Example:
    x = 1
    
    def f():
        y = 3
        return lambda z: x*y > z
    
    lambda_ = f()
    assert lambda_(4), f"validation failed: {lambda_} returned False"
    Assuming the implementation of str for lambdas is just the source, the error message would be:
    validation failed: x*y > z returned False
    
    Prepending the lambda "header", we can identify the parameters, but not distinguish locals vs globals:
    validation failed: lambda z: x*y > z returned False
    
    Again, now that I think of it this isn't really an issue, but just something that came to mind.

I'm not so sure about shortcuts for "implicit lambdas". The lambda expression syntax is already compact enough, and "explicit is better than implicit". This of course doesn't mean such a thing doesn't have a place, for example, as an external package, like your mini-lambda, but I think its benefit is too small in comparison to the added complexity to be added to the language or even the standard library.

@smarie
Copy link
Owner Author

smarie commented Sep 21, 2020

Thanks @plammens for this relevant comment ! Indeed global and local names must be taken into account, and depending on usage some people will wish to resolve them, resolve some of them, or resolve them with a different globals + locals dictionary (a bit like in typing.get_type_hints that accepts custom locals and globals.

The limitation with my mini-lambda is that it forces users to replace their coding habit with another (importing mini_lambda and using the variable symbols inside it to declare their lambdas).

For this reason I would rather prefer to have in the stdlib some helper function lambda_to_str(resolve_closure=False, globals=None, locals=None) or a class method <lambda>.to_str(resolve_closure=False, globals=None, locals=None). If resolve_closure=False (default), the bare lambda expression is returned. If it is True, closure symbols would be replaced with their string representation. Custom globals and locals would enable users to pass other replacement values (objects that would be repr-ed, or directly strings)

That way it would remain optional and allow for the various flexible usages you mention concerning globals and locals. What do you think ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants