Achieving expressiveness in all the ways described above without sacrificing performance is a nontrivial matter. Successive Maude implementations have been advancing this goal while expanding the set of language features. More work remains ahead, but it seems fair to say that Maude, although still an interpreter, is a high-performance system that can be used for many non-toy applications with competitive performance and with many advantages over conventional code. Without in any way trying to extrapolate a specific experience into a general conclusion, a concrete example from the Maude user's trenches may illustrate the point. A formal tool component to check whether a trace of events satisfies a given linear temporal logic (LTL) formula was written in Maude at NASA Ames by Grigore Rosu in about one page of Maude code. The component had a trivial correctness proof--the Maude module was based on the equational definition of the LTL semantics for the different connectives. This replaced a similar component having about 5,000 lines of Java code that had taken over a month to develop by an experienced colleague. The Java tool used a translation of LTL formulas into Büchi automata (the usual method to efficiently model check an LTL formula) and run about three times more slowly than the Maude code. It would have been very difficult to prove the correctness of the Java tool and, having a better and clearly correct alternative in the Maude implementation, this was never done.
Generally and roughly speaking, the current Maude implementation can execute syntactic rewriting with typical speeds from half a million to several million rewrites per second, depending on the particular application and the given machine. Similarly, associative and associative-commutative equational rewriting with term patterns used in practice1.6can be performed at the typical rate of one hundred thousand to several hundred thousand rewrites per second.
These figures must be qualified by the observation that, until recently, the cost of an associative or associative-commutative rewriting step depended polynomially on the size of the subject term, even with the most efficient algorithms. In practice this meant that this kind of rewriting was not practical for large applications, in which the lists or multisets to be rewritten could have millions of elements. This situation has been drastically altered by a recent result of Steven Eker [38] providing new algorithms for associative and associative-commutative rewriting that, for patterns typically encountered in practice, can perform one step of associative rewriting in constant time, and one associative-commutative rewriting step in time proportional to the logarithm of the subject term's size. Maude supports equational rewriting with these new algorithms.
The reason why the Maude interpreter achieves high performance is that the rewrite rules are carefully analyzed and are then semicompiled into efficient matching and replacement automata [36] with efficient matching algorithms. One important advantage of semicompilation is that it is possible to trace every single rewriting step. More performance is of course possible by full compilation. Maude has an experimental compiler for a subset of the language which can typically achieve a fivefold speedup over the interpreter.
Four other language features give the user different ways of optimizing the performance of his/her code. One is profiling, allowing a detailed analysis of which statements are most expensive to execute in a given application (see Section 13.1.4). Another is evaluation strategies (see Section 4.4.7), giving the user the possibility of indicating which arguments and in which order to evaluate before simplifying a given operator with the equations. This can range from ``no arguments'' (a lazy strategy) to ``all arguments'' (an eager bottom-up strategy) to something in the middle (like evaluating the condition before simplifying an if-then-else expression). Evaluation strategies control the positions in which equations can be applied. But what about rules? The analogous feature for rules is that of frozen argument positions; that is, declaring certain argument positions in an operator with the frozen attribute (see Section 4.4.9) blocks rule rewriting anywhere in the subterms at those positions. A fourth useful feature is memoization (see Section 4.4.8). By giving an operator the memo attribute, Maude stores previous results of function calls to that symbol. This allows trading off space for time, and can lead in some cases to drastic performance improvements.
One nagging question may be reflection. Is reflection really practical from a performance perspective? The answer is yes. In Maude, reflective computations are performed by descent functions that move metalevel computations to the object level whenever possible (see Section 11.4). This, together with the use of caching techniques, makes metalevel computations quite efficient. A typical metalevel computation may perform millions of rewrites very efficiently at the object level, paying a cost (linear in the size of the term) in changes of representation from the metalevel to the object level and back only at the beginning and at the end of the computation.