Re: Implicit Times
- To: mathgroup at smc.vnet.net
- Subject: [mg128669] Re: Implicit Times
- From: awnl <awnl at gmx-topmail.de>
- Date: Thu, 15 Nov 2012 03:58:55 -0500 (EST)
- Delivered-to: l-mathgroup@mail-archive0.wolfram.com
- Delivered-to: l-mathgroup@wolfram.com
- Delivered-to: mathgroup-newout@smc.vnet.net
- Delivered-to: mathgroup-newsend@smc.vnet.net
- References: <k7hh3j$nv1$1@smc.vnet.net>
Hi,
> Mathematica assumes Times (*) when two expressions are
> juxtaposed with no explicit intervening binary operator
> (ex., x y is interpreted as x*y).
> I want to change this behavior so it assumes a
> NonCommutativeMultiply (**) instead.
> Is this possible?
It is possible, but I'd hardly recommend to do it, it is probably just
as dangerous as overwriting important internal symbols like Times. What
you want to do is interfering with Mathematica at a very deep level so
be warned to be cautious when playing with these things: errors at that
level might crash or hang the Kernel, the FrontEnd or even the OS (at
least a Windows box). AFAIK there are two possible approaches, either
you can use the hook $PreRead to manipulate the boxes before parsing
(and $Pre to manipulate the unevaluated input) or use MakeExpression
which lets you redefine how boxes are converted to expressions. I think
it is somewhat easier to use $PreRead and $Pre for what you need and
found MakeExpression even more dangerous than those, so I'll stick with
$PreRead and $Pre in the following. You should also note that this
approach might need some changes when you want it to work with InputForm
strings as e.g. when reading package files. What I'll show will in this
form only work in the notebook interface.
Even though the mentioned functions let you manipulate the boxes at a
very early stage of the evaluation process, the conversion of spaces has
already been done, as you can learn from the documentation
(tutorial/LowLevelInputAndOutputRules) and verify with this:
$PreRead=Function[Print[#];#];
a*b c**d
$PreRead=.;
Nevertheless, building on David Baileys tricks with interpreting strings
we can apply the same strategy to manipulate the boxes, but we have to
take special care to not evaluate too early which makes the following
somewhat lengthy. The following definitions will basically do what you want:
$PreRead = Function[
Function[x, MakeBoxes[x, StandardForm], HoldAllComplete] @@ (
MakeExpression[# /. "*" -> "\[Star]", StandardForm] /.
Times -> NonCommutativeMultiply
)];
$Pre = Function[Null, ReleaseHold[HoldComplete[#] /. Star -> Times],
HoldAllComplete];
a (a b)*(c a)
I'm using "\[Star]" as a temporary substitute for "*" here, which looks
exactly like "*" in a notebook but has the advantage that it's
precedence is such that no extra care needs to be taken to keep the
precedence between ** and * (see tutorial/OperatorInputForms in the
documentation for information on operator precedence).
If at all I would only switch this on temporarily where needed, so as
soon as not needed anymore you should evaluate:
$PreRead = .; $Pre = .;
If you really want to use such an approach, I'd recommend to define
helper functions as e.g.:
beginncm[] := (
$PreRead = Function[
Function[x, MakeBoxes[x, StandardForm], HoldAllComplete] @@ (
MakeExpression[# /. "*" -> "\[Star]", StandardForm] /.
Times -> NonCommutativeMultiply
)];
$Pre =
Function[Null, ReleaseHold[HoldComplete[#] /. Star -> Times],
HoldAllComplete];
);
endncm[] := ($PreRead =.; $Pre =.;);
so that you can temporarily switch on the desired behavior without too
much risk of breaking other things:
beginncm[]
expr = a (a b)*(c a);
endncm[]
you will find that this approach has some subtle problems, but it
probably is good enough to define expressions with your prefered syntax.
One of the problems I observed was that e.g. wrappers like FullForm
don't work as expected. The reason for tis is that
MakeBoxes[MakeExpression[#]]& isn't an exact identity (MakeExpression
does obviously does strip some of these wrappers). There could of course
be other side effects that I didn't happen to observe...
hth,
albert