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

Nathan Rice nathan.alexander.rice at gmail.com
Wed Jan 18 14:30:15 CET 2012


> 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

I did some additional thinking about how the interface could be
designed, and I think there might be a good middle ground with regard
to your quoted object.  I still feel like creating variables should
be independent, and use the standard class constructor method.  I feel
like a Context object would be a good place to keep variable values,
and the expression evaluation method.

thus, you might have:

context = Context()
expr = SymbolicObject(name="A") + SymbolicObject(name="B") *
SymbolicObject(name="C", default=5)
context.A = 1
context.B = 2
print context.eval(expr)
11
context.C = 3
print context.eval(expr)
7

> 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.

I don't think it would be too bad to create an AST representation
inside the symbolic expression while building it.

>    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:

Having the evaluate method return an AST with incomplete variable
information would be confusing to me.  I would expect to get a new
symbolic expression with the specified parameters replaced.

>
> 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.

If you build up the AST representation while creating the symbolic
expression, replacing a symbolic expression object should have the
effect of updating the tree.

I think having clearly delineated AST and SymbolicExpr representations
might be easier (possibly via converter functions).  The actual
different may be negligible, but it would serve as an explicit way of
declaring what your expectations are with regard to return values,
etc.

As a side note, it appears that between PyPy object spaces and
continulets, it should be possible to create this without any weird
interpreter hacking.  Hopefully I'll have time to put something
together this weekend.

Nathan



More information about the Python-ideas mailing list