I've restricted function calls to the case where the function expression
is just a symbol, since otherwise it will be hard to visualize.
But with some thought, it may be possible to generalize
this to
ECall [Expr] -- (function:args)
The constructors EOp and EGroup are not used in Sifflet itself,
but they are needed for export to Python, Haskell, and similar languages;
they allow a distinction between operators and functions, and
wrapping expressions in parentheses.
EGroup e represents parentheses used for grouping: (e);
it is not used for other cases of parentheses, e.g.,
around the argument list in a function call.]

Expr as an instance of PyPretty.
This instance is only for Exprs as Python exprs,
for export to Python! It will conflict with the
one in ToHaskell.hs (or Haskell.hs).

The EOp case needs work to deal with precedences
and avoid unnecessary parens.
Note that this instance declaration is for *Python* Exprs.
Haskell Exprs of course should not be pretty-printed
the same way!

Is an expression atomic?
Atomic expressions do not need parentheses in any reasonable language,
because there is nothing to be grouped (symbols, literals)
or in the case of lists, they already have brackets
which separate them from their neighbors.

All lists are atomic, even if they are not literals,
because (for example) we can remove parentheses
from ([a + b, 7])

An operator, such as * or +
An operator is associative, like +, if (a + b) + c == a + (b + c).
Its grouping is left to right if (a op b op c) means (a op b) op c;
right to left if (a op b op c) means a op (b op c).
Most operators group left to right.

We need to be able to say functions are equal (or not) in order
to tell if environments are equal or not, in order to know whether
there are unsaved changes. This is tricky since the primitive
function implementations do not instantiate Eq, so if it's
primitive == primitive? we go by the names alone (there's nothing
else to go by). Otherwise all the parts must be equal.

decideTypes tries to find the argument types and return type
of an expression considered as the body of a function,
at the same time checking for consistency of inputs and
outputs between the parts of the expression.
It returns Right (argtypes, returntype) if successful;
Left errormessage otherwise.