# [Python-ideas] Symbolic expressions (or: partials and closures from the inside out)

Eike Welk eike.welk.lists1 at gmx.de
Sat Jan 14 04:25:50 CET 2012

```I think something like your SymbolicObject class should be in Python's
standard library. Quite a few projects implement similar classes. If there is
a basic infrastructure for symbolic computation in the standard library,
symbolic algorithms can be reused much more simple across projects.

The pattern you employ with SymbolicObject, is a nice way to mix code that is
executed immediately, with code that is executed later. Symbolic algebra
languages, like Maple and Mathematica, function this way too.

I propose however a slightly different interface:

There should be a special object "quoted" to create instances of
"SymbolicObject". The objects should be created in the "__getattribute__"
method. This way the objects know their name, which is quite useful. A
symbolic object would be created like this:

X = quoted.X

You could also write:

const = Constraints(quoted.X * 2 + 1 >= 5, quoted.X % 2 != 0)

The (tree of) symbolic objects should have a method that translate it to an
abstract syntax tree (ast.AST from the standard library). Subsequent
algorithms should operate on this AST. This way symbolic algorithms can also
operate on all possible Python code (SymbolicObject can only create
expressions).

my_ast = (quoted.X * 2 + 1).to_ast()

For convenience I think that all symbolic algorithms should also accept
SymbolicObject, and convert them to ast.AST internally.

The standard library should contain at least these symbolic algorithms:

evalsym(tree, environment, return_type="any")
Evaluates an expression and returns the result. Works similar to:

eval(compile(tree, "", "eval"), environment)

This call would return 7:

evalsym(quoted.X * 2 + 1, {"X":3})

However it should do partial evaluation if some symbols are
unknown, and return an ast.AST in this case (similar to Maple and
Mathematica). This expression should be True:

evalsym(quoted.X + quoted.Y, {"Y":3}) == quoted.X + 3

The optional argument "return_type" specifies the type of the
result. This simplifies algorithms using "eval". Argument
"return_type" can be: "any", "ast", or "object".

substitute(tree, substitutions)
Replaces a symbol with a value (a sub-tree of ast.Ast).
This expression should be True:

substitute(quoted.X + quoted.Y, {"Y": quoted.X * 2}) \
== (quoted.X + quoted.X * 2).to_ast()

Maybe this algorithm should also be able to match general fragments of
the tree and replace them.

Eike.

```