- labels: 460522 --> Lisp Core - Simplification
When more than 1 rule is defined via tellsimpafter for
a given main operator, the rules are hooked together so
that the most recently defined rule calls the rule
before it, before executing itself. The effect is to
make the first rule defined the one that gets to
process the expression first. (The chaining call can be
seen by invoking SYMBOL-FUNCTION on a rule.)
Executing remrule on any rule other than the most
recently defined removes that rule from the rules list,
but the rule remains in the chain, and is executed as
before remrule.
It's possible, I guess, to patch the rule before the
removed rule so that the rule before skips over the
removed rule. Another possibility is to clobber the
definition of the removed rule with a do-nothing stub.
Here is an example:
(%i1) simp: false$
(%i2) tellsimpafter (foo(1), a);
(%o2) [fooRULE1, FALSE]
(%i3) tellsimpafter (foo(1), b);
(%o3) [fooRULE2, fooRULE1, FALSE]
(%i4) simp: true$
(%i5) :lisp (trace |$fooRULE1| |$fooRULE2|)
($fooRULE1 $fooRULE2)
(%i5) foo(1);
0: (|$fooRULE2| ((|$foo|) 1) 1 NIL)
1: (|$fooRULE1| ((|$foo|) 1) 1 NIL) <----
fooRULE1 chained from fooRULE2 here
1: |$fooRULE1| returned |$a|
0: |$fooRULE2| returned |$a|
(%o5) a
(%i6) rules;
(%o6) [TRIGRULE0, TRIGRULE1, TRIGRULE2, TRIGRULE3,
TRIGRULE4, HTRIGRULE1, HTRIGRULE2, HTRIGRULE3,
HTRIGRULE4, fooRULE1, fooRULE2]
(%i7) remrule (foo, fooRULE1); <---- try to kill
fooRULE1 here
(%o7) foo
(%i8) rules;
(%o8) [TRIGRULE0, TRIGRULE1, TRIGRULE2, TRIGRULE3,
TRIGRULE4, HTRIGRULE1, HTRIGRULE2, HTRIGRULE3,
HTRIGRULE4, fooRULE2] <---- fooRULE1 is gone -- OK
(%i9) foo(1);
0: (|$fooRULE2| ((|$foo|) 1) 1 NIL)
1: (|$fooRULE1| ((|$foo|) 1) 1 NIL) <---- ...
but fooRULE1 is called anyway
1: |$fooRULE1| returned |$a| <---- ... and
fooRULE1 returns whatever it returned before it was
supposedly killed
0: |$fooRULE2| returned |$a|
(%o9) a
Above is Maxima 5.9.1 official release on cmucl. Same
behavior observed in 5.9.1cvs, both clisp and gcl. All
on linux.