[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 

    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.


More information about the Python-ideas mailing list