# python-mini-lambda (mini_lambda)¶

*Simple Lambda functions without lambda x: and with string conversion capability*

`repr`

is now enabled by default for expressions and functions! More details here

`mini_lambda`

allows developers to write simple expressions with a subset of standard python syntax, without the `lambda x:`

prefix. These expressions can easily be transformed into functions. It is possible to get a string representation of both.

Among many potential use cases, the original motivation came from valid8 where we want to let users provide their own validation functions, while still being able to raise user-friendly exceptions "showing" the formula that failed.

## Installing¶

```
> pip install mini_lambda
```

## Usage¶

### a- Principles¶

Three basic steps:

- import or create a 'magic variable' (an
`InputVar`

) such as`x`

,`s`

,`l`

,`df`

... - write an
*expression*using it. - transform the
*expression*into a*function*by wrapping it with`_()`

,`L()`

, or`F()`

(3 aliases), or by calling`as_function()`

on it.

For example with a numeric variable:

```
# -- expressions --
from mini_lambda import x
my_expr = x ** 2
my_expr # <LambdaExpression: x ** 2>
my_expr(12) # beware: calling an expression is still an expression !
# <LambdaExpression: (x ** 2)(12)>
# -- functions --
from mini_lambda import _
my_func = _(x ** 2)
my_func # <LambdaFunction: x ** 2>
assert my_func(12) == 144 # calling a function executes it as expected
```

Or with a string variable:

```
# create or import a magic variable, here we import 's'
from mini_lambda import s
# write an expression and wrap it with _() to make a function
from mini_lambda import _
say_hello_function = _('Hello, ' + s + ' !')
# use the function with any input
say_hello_function('world') # Returns "Hello, world !"
# the function's string representation is available
print(say_hello_function) # "'Hello, ' + s + ' !'"
```

### b- Capabilities¶

The variable can represent anything, not necessarily a primitive. If you wish to use another symbol just define it using `InputVar`

:

```
from mini_lambda import InputVar
z = InputVar('z')
from logging import Logger
l = InputVar('l', Logger)
```

Note that the type information is optional, it is just for your IDE's autocompletion capabilities.

Most of python syntax can be used in an expression:

```
from mini_lambda import x, s, _
from mini_lambda.symbols.math_ import Log
# various lambda functions
is_lowercase = _( s.islower() )
get_prefix_upper_shebang = _( s[0:4].upper() + ' !' )
numeric_test_1 = _( -x > x ** 2 )
numeric_test_2 = _( ((1 - 2 * x) <= -x) | (-x > x ** 2) )
complex_identity = _( Log(10 ** x, 10) )
# use the functions
is_lowercase('Hello') # returns False
get_prefix_upper_shebang('hello') # returns 'HELL !'
numeric_test_1(0.5) # returns False
numeric_test_2(1) # returns True
complex_identity(10) # returns 10
# string representation
print(is_lowercase) # s.islower()
print(get_prefix_upper_shebang) # s[0:4].upper() + ' !'
print(numeric_test_1) # -x > x ** 2
print(numeric_test_2) # (1 - 2 * x <= -x) | (-x > x ** 2)
print(complex_identity) # log(10 ** x, 10)
```

If you know python you should feel at home here, except for two things:

`or`

and`and`

should be replaced with their bitwise equivalents`|`

and`&`

- additional constants, methods and classes need to be made lambda-friendly before use. For convenience all of the built-in functions as well as constants, methods and classes from the
`math.py`

and`decimal.py`

modules are provided in a lambda-friendly way by this package, hence the`from mini_lambda.symbols.math_ import Log`

above.

Note that the printed version provides the minimal equivalent representation taking into account operator precedence. Hence `numeric_test_2`

got rid of the useless parenthesis. This is **not** a mathematical simplification like in SymPy, i.e. `x - x`

will **not** be simplified to `0`

.

There are of course a few limitations to `mini_lambda`

as compared to full-flavoured python `lambda`

functions, the main ones being that

- you can't mix more than one variable in the same expression for now. The resulting functions therefore have a single argument only.
`list`

/`tuple`

/`set`

/`dict`

comprehensions are not supported`... if ... else ...`

ternary conditional expressions are not supported either

Check the Usage page for more details.

### New: `repr`

now enabled by default¶

Starting in version 2.0.0, the representation of lambda expressions does not raise exceptions anymore by default. This behaviour was a pain for developers, and was only like this for the very rare occasions where `repr`

was needed in the expression itself.

So now

```
>>> from mini_lambda import x, F
>>> x ** 2
<LambdaExpression: x ** 2>
>>> F(x ** 2)
<LambdaFunction: x ** 2>
```

If you wish to bring back the old exception-raising behaviour, simply set the `repr_on`

attribute of your expressions to `False`

:

```
>>> from mini_lambda import x
>>> x.repr_on = False
>>> x ** 2
(...)
mini_lambda.base.FunctionDefinitionError: __repr__ is not supported by this Lambda Expression. (...)
```

### c- How to support mini-lambda expressions in your libraries.¶

You may wish to support mini-lambda *expressions* (not *functions*) directly into your code. That way, your users will not even have to convert their expressions into functions - this will bring more readability and ease of use for them.

You can do this with `as_function`

: this will convert expressions to functions if needed, but otherwise silently return its input.

```
from mini_lambda import _, s, as_function
def call_with_hello(f):
"""An example custom method that is lambda_friendy"""
# transform mini-lambda expression to function if needed.
f = as_function(f)
return f('hello')
# it works with a normal function
def foo(s):
return s[0]
assert call_with_hello(foo) == 'h'
# with a mini-lambda *Function* (normal: this is a function)
assert call_with_hello(_(s[0])) == 'h'
# and with a mini-lambda *Expression* too (this is new and easier to read)
assert call_with_hello(s[0]) == 'h'
```

In addition a `is_mini_lambda_expr`

helper is also provided, if you wish to perform some reasoning:

```
from mini_lambda import x, is_mini_lambda_expr, as_function
# mini lambda: true
assert is_mini_lambda_expr(x ** 2)
# standard lambda: false
assert not is_mini_lambda_expr(lambda x: x)
# standard function: false
def foo():
pass
assert not is_mini_lambda_expr(foo)
# mini lambda as function: false
f = as_function(x ** 2)
assert not is_mini_lambda_expr(f)
```

## Main features¶

- More compact lambda expressions for single-variable functions
- As close to python syntax as technically possible: the base type for lambda expressions in
`mini_lambda`

,`LambdaExpression`

, overrides all operators that can be overriden as of today in python. The remaining limits come from the language itself, for example chained comparisons and`and/or`

are not supported as python casts the partial results to boolean to enable short-circuits. Details here. - Printability: expressions can be turned to string representation in order to (hopefully) get interpretable messages more easily, for example when the expression is used in a validation context

## See Also¶

The much-broader debate in the python community about alternate lambda syntaxes is interesting, see here

### Equivalent (python-first)¶

I found the following libraries somehow covering the same use case, with more or less success/features:

- SymPy is the most well known symbolic computation framework in python. It provides a printable
`Lambda()`

object, but it does not seem to support all operators (see this post). - lambdaX
- lambdazen. Based on python source code generation at runtime using a decorator. The main drawback is the need to define lambdas inside a decorated function.
- fixing lambda and its associated toy library quicklambda. It is not very exhaustive.
- pyexpression is quite similar to quicklambda (above)
- fz is also inspired by quicklambda (above). Note: it is GPL-licensed.

A bit far from the topic but related:
* letexpr for `let expression`

like Haskell
* calchylus: lisp-like expressions in python based on Hy
* MiniOperators

### String expression-first¶

These libraries create functions from string expressions. Therefore you cannot rely on your favourite IDE to check your expressions, but it might not be a problem for some users/use cases.

- simpleeval
- ... (feel free to suggest more) ...

### Others¶

*Do you like this library ? You might also like my other python libraries*

## Want to contribute ?¶

Details on the github page: https://github.com/smarie/python-mini-lambda