URL: http://www.elsevier.nl/locate/entcs/volume86.html 23 pages
Strategies and User Interfaces in Maude at
Manuel Clavel1,2
Facultad de Informática Universidad Complutense de Madrid Madrid, Spain
Abstract
Maude is a high-level language and a high-performance system supporting executable specification and declarative programming in rewriting logic. Rewriting logic is reflective, in the sense of being able to express its own metalevel at the object level. Reflection is systematically exploited in Maude endowing the language with powerful metaprogramming capabilities, including both user-definable strategies and user-definable interfaces. In this paper we first summarize the main reflective capabilities of Maude, and then we explain their use in a non-trivial interactive metaprogramming application: an inductive theorem prover for Maude implemented in Maude itself.
Key words: Reflection, strategies, user interfaces, Maude.
1 Introduction
Maude [4,5] is a high-level language and a high-performance system supporting both executable specification and declarative programming in rewriting logic [11]. Rewriting logic is a logic for reasoning about concurrent systems having states and evolving by means of transitions. The signature of a rewrite theory describes a particular structure for the states of a system, and the rewrite rules describe which elementary local transitions are possible in the distributed state. The inference rules of rewriting logic allow to deduce general concurrent transitions which are possible in a system satisfying such a description. Since rewriting logic contains equational logic, Maude also supports equational specification and programming. The underlying equational logic chosen for Maude is membership equational logic [12], that has sorts, subsorts, operator overloading, and partiality definable by membership and
1 Research partially supported by Spanish CICYT Project MELODIAS TIC2QÛ2-Q1167.
2 Email: clavel0sip.ucm.es
©2003 Published by Elsevier Science B. V.
equality conditions. In Maude the basic units of specification and programming are called modules, which are of two kinds: functional modules for membership equational logic specifications, and system modules for rewriting logic specifications,
A very important property of rewriting logic is its being reflective [3,8,9], in the sense of being able to express its own metalevel at the object level. Reflection is systematically exploited in Maude endowing the language with powerful metaprogramming capabilities, including both user-definable strategies and user-definable interfaces. Strategies are ways of controlling the execution of Maude modules—that is, of rewrite theories that do not need to be Church-Eosser and terminating. In Maude, strategies are made internal to the logic, that is, they are defined by rewrite rules in a module, and can be reasoned about as with rules in any other module. In fact, there is great freedom for defining many different types of strategies, or even many different strategy languages inside Maude, This can be done in a completely user-definable way, so that users are not limited by a fixed and closed particular strategy language [3,5], Interfaces are ways of interacting with Maude modules—that is, with systems specified by rewrite theories. They include parsing commands, executing them, and pretty printing the results. In Maude, interfaces can be also made internal to the logic, that is, they can be defined by rewrite rules. As for strategies, Maude provides great flexibility for defining many different interfaces thanks to its mixfix front-end and to the use of bubbles [5], The combination of these reflective capabilities, and the good properties of rewriting logic as a logical and semantic framework [13], can be systematically exploited to use Maude as a meta-tool in which many other tools can be easily and efficiently implemented [7],
In this paper we first summarize the main reflective capabilities of Maude, and then we explain how user-definable strategies and user-definable interfaces can be effectively combined in Maude, Our running example is the ITP tool [3,2], an interactive inductive theorem prover for equational specifications fully implemented in Maude using its reflective capabilities. The design and implementation of the ITP tool follows the general methodology for building equational proving tools in Maude proposed in [6], However, our description of the tool updates and completes the ideas contained in [6], since it also covers the design and implementation of the ITP's interface.
Organization
In Sections 2 and 3 we summarize background material about Maude: the language and its reflective capabilities. The contents of these sections are borrowed from [5], Then, in Section 4 we explain how to combine the reflective capabilities of Maude to build an interactive metaprogramming application: an inductive theorem prover for Maude implemented in Maude,
2 The Maude System
Maude [4,5] is a high-level language and a high-performance system supporting executable specification and declarative programming in rewriting logic [11], Since rewriting logic contains equational logic, Maude also supports equational specification and programming. In Maude the basic units are called modules. There are two kinds of modules: functional modules and system modules,
A functional module is an equational style functional program with user-definable syntax in which a number of sorts, their elements, and functions on those sorts are defined. Each functional modules has a name, which is a Maude identifier. An identifier in Maude is any finite string of ASCII characters such that it does not contain any white space,3 For example, a module defining numbers and operations on them can be called NUMBERS, The top-level syntax will then be
fmod NUMBERS is endfm
with ,,' corresponding to all the declarations of submodule importation, sorts, subsorts, operators, variables, equations, and so on,
A sort is declared using the keyword sort followed by an identifier (the sort's name). Multiple sorts may be declared using the keyword sorts followed by a list of identifiers (the sorts' names). For example, we can declare sorts Zero, NzNat. and Nat in the module NUMBERS all at once
sorts Zero Nat NzNat .
A subsort relation on sorts is interpreted as a subset relation on their sets of elements, Subsort inclusions are declared using the keyword subsort. For example, the declarations
subsort Zero < Nat . subsort NzNat < Nat .
say that the sorts Zero and NzNat are subsorts of the sort Nat, A set of subsort declarations defines a partial order among the set of sorts, if no cycles are introduced. This partial order partitions the set of sorts into connected components, that is, into sets of sorts that are directly or indirectly related in the subsort ordering.
An operator is declared with the keyword op followed by its name (a string of characters), followed by the list of sorts of its arguments (called the operator's arity) and the sort of its result (called the operator's coarity), optionally followed by an attribute declaration. If the argument list is empty, the operator is called a constant. Underscores ('_') play a special role in the name of an operator. They indicate the place where arguments must be placed
3 The characters '{', '}', '(', ')', '[', ']' and ',' are special, in that they break a sequence of characters into several identifiers. The backquote character "' is used to indicate that a blank space or the special characters do not break the sequence.
in expressions formed with that operator, Equational attributes in operator declarations are a means of declaring equational axioms in a way that allows Maude to use the corresponding equations efficiently, Maude supports, for example, any combination of the following equational attributes: assoc (associativity), comm (commutativitv), and id: (identity, with the corresponding term for the identity element). Here are some operator declarations for the module NUMBERS.
op zero : -> Zero . op s_ : Nat -> NzNat . op _+_ : Nat Nat -> Nat [assoc comm] . op _*_ : Nat Nat -> Nat [assoc comm] .
The version of equational logic underlying Maude is membership equational logic [12,1], In this logic sorts that belong to the same connected component are grouped into kinds. Maude sorts are user-defined, while kinds are implicitly associated with connected components of sorts and are considered as error super sorts. A kind is named in Maude by enclosing the name of one or more of its sorts in square brackets. The Maude system lifts automatically to kinds all the operators involving sorts of the corresponding connected components to form error expressions. But it is also possible to explicitly declare operators at the kind level. An operator defined at the kind level in general defines only a partial function at the sort level. To emphasize this, Maude supports a notational variant for operator declarations in which an (always total) operator at the kind level can equivalentlv be defined as a partial operator between sorts in the corresponding kinds, with syntax '**>' instead of '->' to indicate partiality.
Variables are constrained to range over particular sorts or kinds, A variable can be declared using the keyword var followed by an identifier (the variable's name), followed by an identifier (its sort) or kind expression (its kind). Multiple variables of the same sort can be declared using the keyword vars, Here are some variable declarations for the module NUMBERS,
vars N M I : Nat . vars X Y : [Nat].
A term is either a constant, a variable, or the application of an operator to a list of argument terms, which must agree with the declared aritv of the operator, that is, must be of the same length, and each term must have sort (or at least kind) in the connected component of the corresponding declared argument sorts. If a module's grammar is unambiguous, then each term has a single kind, namely, the result kind of its topmost operator. But we can also associate sorts to terms. Specifically, constants and variables have the sorts they are declared with and any supersort of it. And given a term of the form f(t\,..., tn), if ti has sort Si, for i = 1,,,,, n, and there is an operator declaration op f :s\.. .sn->sthen f(t\,... ,tn) has sort s and any of its supersorts. For example, in the module NUMBERS the term s s zero has sorts NzNat and Nat.
Unconditional equations are declared using the keyword eq, followed by
two terms (its lefthand side and its righthand side), optionally followed by a list of statement attributes. Unconditional membership axioms are declared with the keyword mb followed by a term, followed by a sort. As for equations, memberships can optionally have statement attributes. For example, we can include in the module NUMBERS equations axiomatizing the addition operation as follows
eq N + zero =N. eqN+sM=s(N+M) .
Statement attributes have different uses: in particular, the label attribute followed by an identifier names a statement, and the nonexec attribute indicates that a statement must be ignored by the Maude rewrite engine. For example, we can add the distributive law as a labelled, non-executable statement to the module NUMBERS
eq (N + M) * I = (N * I) + (M * I) [nonexec label distr-law] .
Although non-executable, this statement is part of the semantics of the module and can for example be used at the metalevel for controlled execution or theorem proving purposes.
Conditional equations and conditional membership axioms are declared, respectively, with the keywords ceq and cmb. Equality conditions in conditional equations and memberships are made of individual equations and memberships, A condition can be either a single equation, a single membership, or a conjunction of equations and memberships using the binary conjunction connective /\ which is assumed associative. The satisfaction of the conditions is attempted sequentially. Equations in conditions can be ordinary equations t = t', matching equations t := t', or abbreviated, Boolean4 equations of the form t, with t a term in the kind [Bool] , abbreviating the equation t = true. In the execution of a matching equation t := t', the variables in the left-hand side t which are not yet instantiated become instantiated by matching t against the canonical form of the righthand side t', if t is a pattern.
A system module specifies a rewrite theory. A rewrite theory has sorts, kinds, and operators, and can have three types of statements: equations, memberships, and rules, all of which can be conditional. Computationally, rewrite rules specify local concurrent transitions that can take place in a system if the pattern in the rule's lefthand side matches a fragment of the system state and the rule's condition is satisfied. In that case, the transition specified by the rule can take place, and the matched fragment of the state is transformed into the corresponding instance of the righthand side. The top-level syntax for system modules is as for functional modules, except that fmod and endfm are replaced, respectively, by mod and endm. Module importations, sort and subsort declarations, operator declarations, variable declarations, and equation
4 By default, any Maude module imports the predefined BOOL module [5]. This module declares the two Boolean constants true and false, and three Boolean polymorphic operators: if_then_else_f i (with the expected meaning), _==_ (equality), and _=/=_ (inequality).
and membership statements are exactly as for functional modules. Unconditional rules are introduced with the keyword rl followed by an identifier (the rule's label), and two terms (its lefthand side and its righthand side). Conditional rewrite rules are introduced with the keyword crl and can have very general conditions involving equations, memberships and other rewrites,
3 Reflection in Maude
Informally, a reflective logic is a logic in which important aspects of its meta-theorv can be represented at the object level in a consistent way, so that the object-level representation correctly simulates the relevant metatheoretic aspects. Rewriting logic is reflective [3,8,9] in a precise mathematical sense, namely, there is a finitely presented rewrite theory U that is universal in the sense that we can represent in U any finitely presented rewrite theory 7Z (including U itself) as a term 7Z, any terms t, t' in 1Z as terms t, t', and any pair (7Z,t) as a term (7Z,t), in such a way that we have the following equivalence
R b /—>t' U b (RJ)—>(%t>).
Since U is representable in itself, we can achieve a reflective tower with an arbitrary number of levels of reflection:
Uht^t' & U b (n,t) (TZ,f) & U b (U,(TZ,t)) (U,(n,f))...
Maude's language design and implementation make systematic use of the fact that rewriting logic is reflective. This is achieved in Maude through its predefined module META-LEVEL, In this module, key functionality of the universal theory U has been efficiently implemented: Maude modules can be metarepresented as terms of sort Module, which can then be manipulated and transformed by appropriate built-in functions. In the rest of this section we introduce the reflective capabilities of Maude that will be used in the following section: namely, how Maude's sorts, kinds, terms, sets of assignments, and sets of equations can be metarepresented, respectively, as terms of sort Sort, Kind, Term, Substitution, and EquationSet; and how the metalevel functions of reducing a term to normal form, matching two terms at the top, and parsing and pretty printing a term in a module are available to the user in an efficient way through the built-in functions metaReduce, metaMatch, metaParse, and metaPrettyPrint, A full description of the module META-LEVEL can be found in [5, Chapter 10],
Sorts and kinds are metarepresented as specific subsorts of the sort Qid of quoted identifiers. The sort Qid is declared in the predefined module QID, which is imported by the module META-LEVEL, A term of sort Sort is any quoted identifier not containing the following characters: ':', '.', ',', '[', and ']', e.g. 'Nat. An element of sort Kind is a quoted identifier of the form '' ISortList1 ] where SortList is a single identifier formed by a list of unquoted elements of sort Sort separated by backquoted commas, e.g, '' [Zero' ,NzNat]. The sort Type is then the union of Sort and Kind.
Terms are metarepresented as terms of the sort Term, The base eases are given by subsorts Constant and Variable of the sort Qid, Terms of sort Constant are quoted identifiers that contain the constant's name and its type separated by a ".", e.g., 'zero .Zero. Similarly, terms of sort Variable contain the variable's name and its type separated by a ":", e.g., 'N:Nat. Then a term of the form f(t\,... ,tn) is metarepresented by applying the operator _ [_] to the quoted form of the identifier / and to the metarepresentation of the list of terms ti,...,tn. Lists of terms are metarepresented as terms of sort TermList by applying the associative operator _,_ to the metarepresentation of the terms in the list. For example, the term s zero + zero is metarepresented by the term ' _+_ ['s_ ['zero .Zero] , 'zero. Zero], Here are the sorts, subsort relations, and operator declarations to metarepresent terms in the module META-LEVEL,
sorts Constant Variable Term . subsort Constant < Term . subsort Variable < Term . sort TermList . subsort Term < TermList .
op : TermList TermList -> TermList [assoc] . op _[_] : Qid TermList -> Term .
Since terms in the module META-MODULE can be metarepresented just as terms in any other module, the metarepresentation of terms can be iterated.
Assignments of terms to variables are metarepresented as terms of the sort Assignment using the operator _<-_. Sets of assignments are then metarepresented as terms of the sort Substitution using the operator _;_ which is declared associative, commutative, and with identity element none. Here are the sorts, subsort relations, and operator declarations to metarepresent sets of assignments in the module META-LEVEL.
sorts Assignment Substitution . subsort Assignment < Substitution . op _<-_ : Variable Term -> Assignment . op none : -> Substitution .
op : Substitution Substitution -> Substitution [assoc comm id: none] .
Equations, equational conditions, and statement attributes are metarepresented as terms of the sorts Equation, EqCondition, and AttrSet with a syntax very similar to Maude's syntax. The difference, of course, is that now terms and sorts in equations, memberships, and equality conditions are metarepresented as explained above. Sets of equations are then metarepresented as terms of the sort EquationSet using the operator __ which is declared associative, commutative, and with identity element none. Here are the sorts, subsort relations, and operator declarations to metarepresent sets of equations
in the module META-LEVEL,
sort EqCondition .
op nil : -> EqCondition .
op _=_ : Term Term -> EqCondition .
op _:_ : Term Sort -> EqCondition .
op _:=_ : Term Term -> EqCondition .
op _/\_ : EqCondition EqCondition -> EqCondition
[ctor assoc id: nil] . sorts Equation EquationSet . subsort Equation < EquationSet . op eq_=_[_] . : Term Term AttrSet -> Equation . op ceq_=_if_[_] . : Term Term EqCondition AttrSet -> Equation . op none : -> EquationSet .
op __ : EquationSet EquationSet -> EquationSet [assoc comm id: none] .
The built-in function metaReduce takes as arguments the metarepresen-tation of a module 1Z and the metarepresentation of a term t, and it returns the metarepresentation of the fully reduced form of t, using the equations in 7Z, together with the metarepresentation of its corresponding sort or kind. Appropriate selectors extract from the result pair its two components. The reduction strategy used by metaReduce is the Maude's default reduction strategy for functional modules. Here are the sorts and operator declarations for metaReduce,
sort ResultPair .
op {-,-} : Term Type -> ResultPair . op metaReduce : Module Term ~> ResultPair . op getTerm : ResultPair -> Term . op getType : ResultPair -> Type .
The built-in function metaMatch takes as arguments the metarepresentation of a module 7Z, the metarepresentations of two terms t and t', the metarepresentation of an equality condition Cond, and a natural number n. This function tries to match at the top the terms t and t' in the module 1Z in such a way that the resulting substitution satisfies the equality condition Cond. The last argument is used to enumerate possible matches. If the matching attempt is successful, the result is the corresponding substitution; otherwise, noMatch is returned. Here are the sorts, subsorts, and operator declarations for metaMatch,
sorts Assignment Substitution . subsort Assignment < Substitution . op _<-_ : Variable Term -> Assignment . op none : -> Substitution
op _;_ : Substitution Substitution -> Substitution
[assoc comm id: none] . sort Condition Substitution? .
subsort Substitution < Substitution? . subsort EqCondition < Condition . op noMatch : -> Substitution? .
op metaMatch : Module Term Term Condition Nat ~> Substitution? .
The sort Nat contains the natural numbers. This sort is declared in the predefined module NAT which is imported by the module META-LEVEL,
The built-in function metaParse takes as arguments the metarepresenta-tion of a module 7Z, a list of quoted identifiers, and a value of the sort Type?, i.e, either the metarepresentation of a type or the constant any Type, Lists of quoted identifiers are terms of sort QidList and are built with the operator __ which is declared associative with the identity element nil. The function metaParse tries to parse the corresponding list of identifiers as a term of the given type in the module 7Z; the constant anyType allows any type. If metaParse succeeds, it returns the metarepresentation of the parsed term with its corresponding sort or kind. Here are the sorts, subsorts, and operator declarations for metaParse,
sort QidList . subsort Qid < QidList . op nil : -> QidList .
op __ : QidList QidList -> QidList [assoc id: nil] .
sort Type? .
subsort Type > Type? .
op anyType : -> Type? .
sort ResultPair? .
subsort ResultPair < ResultPair? .
op metaParse : Module QidList Type? ~> ResultPair?
Finally, the built-in function metaPrettyPrint takes as arguments the metarepresentation of a module 1Z and the metarepresentation of a term t, and it returns a list of quoted identifiers that metarepresents the string of tokens produced by pretty printing the term t in the signature of 1Z. Here are the operator declaration for metaPrettyPrint,
op metaPrettyPrint : Module Term ~> QidList .
4 Strategies and User Interfaces in Maude
In this section we explain how to combine the reflective capabilities of Maude, summarized in Section 3, to build an interactive application in Maude, We organize the material in four sections, corresponding to the different subtasks comprised in the implementation of a particular application in Maude: we explain first, in Section 4,1, how to define a read-eval-print loop for the application; then, in Section 4,2, how to define the syntax for the commands; next, in Section 4,3, how to define the interaction with the loop; and finally, in Section 4,4, how to define the processing of the commands. To illustrate the
methodology proposed in each section, we use as a running example parts of the actual implementation of the ITP tool [3,2], This interactive application is an inductive theorem prover to verify properties of Maude functional modules which is fully implemented in Maude itself in a module named ITP-TOOL, In fact, the ITP tool is an interactive metaprogramming application, since it must take Maude functional modules as arguments and perform different analysis and transformations, like extracting the appropriate structural induction principles or adding the corresponding induction hypothesis, on such modules,
4-1 The read-eval-print loop
Maude provides a general input/output facility through its predefined module LOOP-MODE, This module declares an operator [_,_,_] that can be seen as an object of sort System—that we call the loop object— with an input stream (the first argument), an output stream (the third argument), and a state (given by its second argument),
sorts State System .
op [-,-,-] : QidList State QidList -> System .
The way to distinguish the inputs passed to the loop object from the inputs passed to the Maude system is by enclosing the former in parentheses. When something is written in the Maude prompt enclosed in parentheses it is converted into a list of quoted identifiers, which is then placed in the first slot of the loop object. The output is handled in the reverse way, that is, a list of quoted identifiers placed in the third slot of the loop object is printed on the terminal after unquoting each of the identifiers in the list. The state of the loop object has been declared in a completely generic way. In fact, the sort State does not have any constructor in the module LOOP-MODE, This gives complete flexibility for defining the terms that represent the state of the loop object in each particular application.
The sort State in the ITP tool is inherited from Full Maude [10], This is an application, implemented in Maude in a module named FULL-MAUDE, which is imported by the module ITP-TOOL, The module FULL-MAUDE, that extends the modules META-LEVEL and LOOP-MODE, endows Maude with a powerful and extensible module algebra in which Maude modules can be combined together to build more complex modules. In each session, the state of Full Maude is an object which maintains the database of the system. This object has an attribute db, to keep the actual database in which all the modules being entered are stored, and two attributes input and output to simplify the interaction with the database (do not confuse these attributes of the state of the loop object with the first and last slots of the loop object itself). Here are the sorts, subsorts, and operator declarations that define the state of the loop object in Full Maude,
sorts Oid Cid AttributeSet .
subsort Object < State .
op none : -> AttributeSet .
op : AttributeSet AttributeSet -> AttributeSet
[assoc comm id: none] . op <_:_!_> : Oid DatabaseClass AttributeSet -> Object . sort Database .
op db :_ : Database -> Attribute . op input :_ : TermList -> Attribute . op output :_ : QidList -> Attribute .
In the ease of the ITP, as we will explain in Section 4,3, the input attribute holds the next request to be executed by the tool, while the output attribute holds the next response to be output to the user. Also, the state of the loop object in the ITP contains an additional attribute proof State that holds the state of the proof in each session,
sort ProofState .
op proofState :_ : ProofState -> Attribute .
A proofstate is represented by a triple formed by the set of goals to be proved, the trace of the proof up to that point, and the lemmas to be added to certain modules when the proofs of certain goals are completed,
sorts GoalSet ProofTrace LemmaSet .
op <_;_;_> : GoalSet ProofTrace LemmaSet -> ProofState .
For the sake of space limitations, we describe only the syntax for representing the sets of goals in a proof state. First, a goal G is represented by a 5-tuple that contains: the representation of the label, label a, of the goal; the metarepresentation of the name, name(modulec), of the module, modulea, related with the goal; the representation of the formula, formulaG, to be proved; and two natural numbers, varnuma and hypnumG, that are used to generate (fresh) new variables and (fresh) new labels for hypothesis during the proof of the goal. Goal labels are represented as terms of sort String, This sort contains strings of characters and is declared in the predefined module STRING, which is imported by the module META-LEVEL, Formulas are represented with the operators equality and sortP (for equality and membership assertions), conjunction and implication (for conjunctive and implicative formulas), and VQuantif i cat ion (for universally quantified formulas). Finally, sets of goals are represented with the operator goalSet, which is declared associative, commutative, and with identity element emptyGoalSet,
sorts VarList Equality Membership Formula . subsort Variable < VarList . subsort Equality < Formula . subsort Membership < Formula . op nilVarList : -> VarList .
op _:_ : VarList VarList -> VarList [assoc id: nilVarList] . op equality : Term Term -> Equality . op sortP : Term Qid -> Membership .
op conjunction : Formula Formula -> Formula [assoc comm] . op implication : Formula Formula -> Formula . op VQuantification : VarList Formula -> Formula . subsort Goal < GoalSet .
op prove : String Nat Nat Qid Formula -> Goal . op emptyGoalSet : -> GoalSet . op goalSet : GoalSet GoalSet -> GoalSet
[assoc comm id: emptyGoalSet] .
4-2 Tokens and bubbles
Maude provides great flexibility to define the syntax for an object language or a tool thanks to its mixfix front-end and to the use of bubbles (any nonempty list of Maude identifiers) [5]. The idea is that for a language (resp, a tool) that allows modules (resp, commands) with user-definable syntax its syntax can be seen as a combined syntax at two different levels: what we may call the top-level syntax of the language (resp, the tool), and the user-definable syntax introduced in each module (resp, command). Bubbles provides a way to reflect this duality. Similar ideas have been exploited using ASF+SDF [14].
In the case of the ITP, the syntax of its commands is defined using three sorts of bubbles: the sort Token for bubbles of length one, also called tokens; the sort Bubble for bubbles of any length; and the sort NeTokenList for bubbles of any length greater that one. To illustrate the use of bubbles, we explain the definition of the syntax of the command for adding a goal to the proof state; the syntax for the other commands is defined analogously (two other examples of command syntax definitions are given at the end of this section). All the syntax definitions for ITP commands are contained in the module ITP-GRAMMAR, They have in common that a valid command is always a term of sort Input,
To express the command for adding a goal G to the proof state the user must employ the operator goal_:_ with two arguments: the label labels to identify the goal and the goal G itself. To label a goal the user can employ any Maude identifier, that is, any element of the sort Token, and to state a goal G the user must employ the operator also with two arguments: the name name(modulea) of the functional module module'.q related with the goal, and the formula formulaG to be proved,
sort Goal .
op goal_:_. : Token Goal -> Input . op : Token UserFormula -> Goal .
Finally, to declare a formula the user must employ the syntax provided by the following sorts, subsorts, and operator declarations.
sorts UserVarList UserEquality UserMembership UserFormula . subsort Token < UserVarList . subsort UserEquality < UserFormula .
subsort UserMembership < UserFormula .
op _=_ : Bubble Bubble -> UserEquality .
op _:_ : Bubble Token -> UserMembership .
op _=>_ : UserFormula UserFormula -> UserFormula .
op _&_ : UserFormula UserFormula -> UserFormula [comm assoc] .
op : UserVarList UserVarList -> UserVarList [assoc] .
op {-}(-) : UserVarList UserFormula -> UserFormula [none] .
Notice how we explicitly declare operators that correspond to the top-level syntax of membership equational formulas—namely, {_}(_), _&_, _=>_, _=_, _: _, And notice also how we use the sorts Token or Bubble to indicate those pieces of a formula—namely, variables, terms and sorts—that can only be parsed with the signature declared in the functional module related with the goal.
We end this section with the syntax definitions of two commands that simplify, using two different reduction strategies, a goal G consisting of an equality t = t'. The first command, (rew labels •), reduces both sides of the equality, t and t', in the module moduleG, using the Maude's default strategy. The second command, (apply id to labelG at pos with subs .), reduces only the lefthand side of the equality, t, applying one of the equations labelled id in the module modulea, partially instantiated with the substitution subst, at the subterm that occupies the position pos in t. For the sake of space limitations, we omit here the syntax that the user must employ for expressing positions in a term and assignments for variables in an equation,
sorts UserPosition UserSubstitution . op rwr_. : Token -> Input [none] .
op apply_to_at_with'(_'). : Token Token UserPosition UserSubstitution -> Input .
4-3 Interacting with the loop
In Section 4,1 we explained how the module LOOP-MODE provides a generic read-eval-print loop for applications implemented in Maude, in the form of an object with an input slot, an output slot, and a state; and we also illustrated how the state of this loop object can be tailored for each particular application. Then, in Section 4,2 we explained how the syntax of the applications can be declared in a Maude module using the Maude mixfix front-end and the bubbles datatype. Now we will explain how the interaction with the loop object in each particular application can be defined using rewrite rules in an appropriate extension of the modules META-LEVEL and LOOP-MODE,
Recall that the user of an application implemented in Maude makes a request by enclosing the text in parentheses, and that this text is then automatically converted into a list of quoted identifiers and placed in the input slot of the loop object; recall also that the output is handled in the reverse way, that is, the list of quoted identifiers placed in the output slot of the loop
object is printed on the terminal after unquoting each of the identifiers in the list. The implementation in Maude of an application will then contain rewrite rules acting on loop objects, that is, on terms of sort System built with the operator [_,_,_], to detect, looking at their input and output slots, that is, at the first and last arguments of [_,_,_], when a valid request has been entered by the user (and it must be processed), or when a valid result has been produced by the application (and it must be output). As we explain below, detecting valid requests can be easily and efficiently achieved using the built-in operation metaParse,
In the case of the ITP, the rule [in] checks when a list of quoted identifiers placed in the input slot of its loop object corresponds to a valid command, that is, to a term of sort Input in the module ITP-GRAMMAR, and it places the metarepresentation of this term in the input attribute of the state of the loop object. The constant nilTermList is used to indicate that the tool is idle. The constant META-ITP-GRAMMAR is made equal to the metarepresentation of the module ITP-GRAMMAR, but we omit here the declaration of the corresponding equation, META-ITP-GRAMMAR = ITP-GRAMMAR.
op ITP : -> DatabaseClass .
op nilTermList : -> TermList .
op META-ITP-GRAMMAR : -> Module .
vars QIL QIL' QIL" : QidList .
var 0 : Oid .
var Atts : AttributeSet .
crl [in] :
[QIL, < 0 : ITP | input : nilTermList, Atts >, QIL5] =>
< 0 : ITP | input : getTerm(metaParse(META-ITP-GRAMMAR,
QIL, 'Input)),
Atts >,
if QIL =/= nil /\ metaParse(META-ITP-GRAMMAR,
QIL, 'Input): ResultPair .
Suppose, for example, that the user enters the command
(1) (goal id-0 : NUMBERS |- {N:Nat}(0 + N = N) .)
The text enclosed in parenthesis in (1) is first automatically converted into the list of quoted identifiers
(2) 'goal 'id-0 ': 'NUMBERS ' I- "{ 'N:Nat "} " ( '0 '+ 'N '= 'N ") ' .
which is then placed in the input slot of the loop object. The rule [in] checks then, using the built-in operation metaParse, whether the list of identifiers resulting from unquoting the quoted identifiers in (2) corresponds to a term of sort Input in the module ITP-GRAMMAR. In this example, metaParse returns a term of sort ResultPair formed by the term
(3) 'goal_:_. ['token["id-0.Qid] ,
'_!-_[5 token[5 5 NUMBERS.Qid],
5 ,{_,},_'['token[' 'N:Nat.qid] ,
5_=_[5bubble[5_[5 'O.Qid,5 '+.Qid,5 'N.Qid]] , 'bubble[''N.Qid]]]]]
of sort Term and by the term 'Input of sort Type. The condition of the rule [in] is therefore satisfied and the term (3) is placed in the input attribute of the state of the loop object.
For the inverse direction of the interaction, the rule [out] checks when the output attribute of the state of the loop object holds a response to be output, that is, a term of sort QidList different from nil, and it places it in the output slot of the loop object.
crl [out] :
[QIL, < 0 : ITP I output : QIL', Atts >, QIL"] => [QIL, < 0 : ITP I output : nil, Atts >, (QIL' QIL")] if QIL' =/= nil .
4-4 Processing requests
In Section 4.3 we explained how the interaction between a user and an application implemented in Maude can be defined, in an appropriate extension of the modules META-LEVEL and LOOP-MODE, by rewrite rules acting on the loop objects defined for that application, that is, acting on terms of sort System. Now we will illustrate how the processing of the requests made to an application can also be defined by rewrite rules acting, in this case, on the states of the loop objects defined for that application, that is, acting on terms of sort State. Our examples will illustrate as well the use of the Maude metalevel built-in functions, like metaParse, metaPrettyPrint, metaReduce and metaMatch, to easily and efficiently define operations on modules and terms, including user-defined reduction strategies for modules and terms.
In the case of the ITP, the rule [goal] defines the processing of a command of the form (goal labels G). Recall that with this command the user requests the addition of a new goal G to the proof state. The ..' corresponds to additional equational conditions that we omit here; we also omit the definitions of some of the auxiliary functions that are used in this rule.
op downQid : Term -> Qid . op extractFormula : Term -> Formula . op newLabel : Qid -> String . op newModName : Qid -> Qid . op getModule : Qid Database -> Module .
op meta-pretty-print-GoalSet : GoalSet Database -> QidList .
vars NewDB : Database . vars T1 T2 T3 : Term .
var SelGoal : Formula .
vars Goals NewGoals : GoalSet .
vars PT NewPT : ProofTrace .
var Lemmas NewLemmas : LemmaSet . var NewLabel : String . var SelModMN NewMN : ModName . var SelMod : Module . crl [goal] :
< 0 : ITP I db : DB,
input : (5 goal_:_.[5 token[T3], I-_[5token[Tl], T2]]), proofState : < Goals ; PT ; Lemmas >, output : nil, Atts >
< 0 : ITP I db : NewDB,
input : nilTermList,
output : meta-pretty-print-GoalSet(NewGoals, NewDB), proofState : < NewGoals ; NewPT ; NewLemmas >, Atts >
SelModMN := downQid(Tl) /\
SelMod := getModule(SelModMN, DB) /\
NewLabel := newLabel(T3) /\
NewMN := newModName(T3) /\
SelGoal := extractFormula(T2, SelMod) /\
NewGoals := goalSet(prove(NewLabel, 0, 0, NewMN, SelGoal), Goals) /\ ... •
The particular form of the lefthand side of the rule [goal] , and in particular of the pattern in the input attribute, should be clear from our example in Section 4.2. The righthand side of this rule contains, however, several variables that do not appear in its lefthand side. During the execution of the rule [goal], these new variables will become instantiated by solving matching equations in the condition of the rule. First, the variable SelModMN is instantiated, using the function downQid, with the metarepresentation of the name name (module a)- The function downQid takes the metarepresentation of a quoted identifier and returns that quoted identifier. Then, the variable SelMod is instantiated with the metarepresentation of moduleG, which is obtained, using the function getModule, from the database. Next, the variable NewLabel is instantiated, using the function newLabel, with a string of characters based on the label lahelc■ Similarly, the variable NewMN is instantiated, using the function newModName, with a quoted identifier based on the name
name (module a). Then, the variable NewDB is instantiated with the result of adding the metarepresentation of a copy of modules to the database,5 such that the metarepresentation of the name of the new module is the value of the variable NewMN. Next, the variable SelGoal is instantiated, using the function extractFormula, with the formula, formulaG. This function converts the metarepresentation of a term of sort UserFormula into a term of sort Formula by replacing, using the function metaParse, each metarepresentation of a bubble or token inside the metarepresentation of an equation or a membership assertion with the metarepresentation of the corresponding term or type. The auxiliary function extractVarList converts the metarepresentation of a term of sort UserVarList into a term of sort VarList, and the auxiliary function downQidList takes the metarepresentation of a list of quoted identifiers and returns that list of quoted identifiers,
op extractFormula : Term Module ~> Formula . op extractVarList : Term Module ~> VarList . op downQidList : Term -> QidList . eq extractFormula(5'{_'}'(_')[Tl, T2] , Mod) = VQuantification(extractVarList(Tl, Mod), extractFormula(T2, Mod)), eq extractFormula(5_=_['bubble[Tl], 'bubble[T2]], Mod)
= equality(getTerm(metaParse(Mod, downQidList(Tl), anyType)), getTerm(metaParse(Mod, downQidList(T2), anyType))). eq extractFormula('_:_['bubble[Tl], 'token[T2]], Mod)
= sortP(getTerm(metaParse(Mod, downQidList(Tl), anyType)), downQid(T2)) . eq extractFormula('_=>_[Tl, T2] , Mod)
= implication(extractFormula(Tl, Mod),extractFormula(T2, Mod)), eq extractFormula('_&_[Tl, T2], Mod)
= conjunction(extractFormula(Tl, Mod),extractFormula(T2, Mod)).
Finally, the variable NewGoals is instantiated with the result of appending, using the constructor goalSet, the representation of the new goal G (which is obtained from the values of the variable NewLabel. NewMN, and SelGoal) to the previous set of goals.
The rule [goal] also transforms the new set of goals, using the auxiliary function meta-pretty-print-GoalSet, into a list of quoted identifiers, and places the result in the output attribute of the state of the loop object. As explained above, the rule [out] will then take from there the list of quoted identifiers and place it in the output slot of the loop object, ready to be printed by the system on the terminal after unquoting each of the identifiers in the list. The function meta-pretty-print-GoalSet is defined recursively on terms of sort GoalSet, and it calls several other auxiliary functions, like the function meta-pretty-print-Formula that transforms a term of sort
5 Since several goals can be attempted simultaneously over the same module TZ, each of the goals is associated with a different copy of the module TZ.
Formula into a list of quoted identifiers. In particular, here is the declaration of meta-pretty-print-Formula and the equation that defines this function for terms of sort Equality,
op meta-pretty-print-Formula : Module Formula -> QidList . eq meta-pretty-print-Formula(Mod, equality(Tl, T2))
= metaPrettyPrint(Mod, Tl) '= metaPrettyPrint(Mod, T2) .
Notice how the built-in function metaPrettyPrint is used to automatically obtained, in quoted form, the list of identifiers produced by pretty printing a term in the signature of a module.
Our second example is the rule [rwr] that defines the processing of a command of the form (rwr labela , when formulaG is an equality t = t'. Recall that with this command, the user requests the reduction of both sides of the equality t = t' using Maude's default reduction strategy. As before, ,,' indicates additional equational conditions that are omitted, and we also omit the definitions of some of the auxiliary functions that are used in this rule,
op extractString : Term -> String .
op applyReduce : Equality Module -> Equality .
var SelLabel : String .
var SelVarNum : Nat .
var SelHypNum : Nat .
var SelMod : Module .
var SelGoal : Formula .
crl [rwr] :
< 0 : ITP | db : DB,
input : (5rwr_.[5token[Tl]]), proofState : < Goals ; PT ; Lemmas >, output : nil, Atts >
< 0 : ITP | db : NewDB,
input : nilTermList,
output : meta-pretty-print-GoalSet(NewGoals, NewDB), proofState : < NewGoals ; NewPT ; NewLemmas >, Atts >
SelLabel := extractString(Tl) /\
NewGoal := applyReduce(SelGoal, SelMod) /\
NewGoals := goalSet(prove(SelLabel, SelVarNum, SelHypNum,
SelModMN, NewGoal), removeFrom(SelLabel, Goals)) .
/\ ... •
The lefthand side of this rule is analogous to the lefthand side of the rule [goal], The righthand side of the rule contains also several variables that do not appear in its lefthand side, but that will become instantiated by solving matching equations in the condition of the rule. First, the variable SelLabel is instantiated, using the function extractString, with the representation of the label label a- This function converts the metarepresentation of a term of sort Token into a term of sort String, Then, the variables SelVarNum and SelHypNum are instantiated by matching equations (that are omitted) with varnwmG and hypnumG, the variables SelMod and SelModMN with the metarep-resentations of moduleG and name(moduleG), and the variable SelGoal with the representation of formulaG. Next, the variable NewGoal is instantiated, using the function applyReduce, with the representation of the equality that results from reducing in moduleG both sides of I = /' using Maude's default reduction strategy. The definition of applyReduce is as follows:
vars T1 T2 : Term . var Mod : Module . eq applyReduce(equality(Tl, T2), Mod)
= equality(getTerm(metaReduce(Mod, Tl)),
getTerm(metaReduce(Mod, T2))) .
Notice how the built-in operation metaReduce is used to automatically reduce both sides of the equality with Maude's default reduction strategy. Finally, the variable NewGoals is instantiated with the result of appending, using the constructor goalSet, the value of NewGoal to the previous set of goals, from which G has been removed using the operation removeFrom,
Our final example is the rule [applyAtWith], This rule defines the processing of a command of the form (apply id to labelG at pos with subs .), when id is a label, formulaG is an equality t = t', pos is a position in t, and subs is a list of assignments in module a. Recall that with this command the user requests the application of any of the equations labelled id in moduleG, partially instantiated with the substitution subs, to the term t at position pos. Once again, ',,,' indicates additional equational conditions that are omitted, and we also omit the definitions of some of the auxiliary functions that are used in this rule,
op extractPos : Term -> Position .
op extractSubst : Term Module -> Substitution .
op getLabelEqs : Qid EquationSet -> EquationSet .
op applyApply : Equality Position Substitution EquationSet Module
-> Equality . var SelPos : Position . var SelSubst : Substitution . var SelEqs : EquationSet . crl [applyAtWith] :
< 0 : ITP | db : DB,
input : (5 apply_to_at_with' (_') .
['token[T2], 'token[Tl], 'token[T3], T4] ), proofState : < Goals ; PT ; Lemmas >, output : nil, Atts >
< 0 : ITP I db : NewDB,
input : nilTermList,
output : meta-pretty-print-GoalSet(NewGoals, NewDB), proofState : < NewGoals ; NewPT ; NewLemmas >, Atts >
SelLabel := extractString(Tl) /\
SelPos := extractPos(T3) /\
SelSubst := extractSubst(T4, SelMod) /\
SelEqs := getLabelEqs(downQid(T2), SelMod) /\
NewGoal := applyApply(SelGoal, SelPos, SelSubst, SelEqs, SelMod) /\
NewGoals := goalSet(prove(SelLabel, SelVarNum, SelHypNum,
SelModMN, NewGoal), removeFrom(SelLabel, Goals))
The lefthand side of this rule is analogous to the lefthand side of the rules [goal] and [rwr], Also, as in the rules [goal] and [rwr], the variables in the righthand side of this rule that do not appear in its lefthand side will become instantiated by solving the matching equations in its condition. First, the variables SelLabel, SelVarNum, SelHypNum, SelMod, and SelGoal are instantiated by matching equations (some of them are omitted) as in the rule [rwr], Then, the variables SelPos and SelSubs are instantiated, respectively, with representations of pos and subs using the functions extractPos and extractSubst, The function extractPos converts the metarepresentation of a term of sort Token into a term of sort Position (whose definition is omitted here). The definition of this function is analogous to the definition of extractString, The function extractSubst converts the metarepresentation of a term of sort UserSubstitution into a term of sort Substitution, The definition of this function is analogous to the definition of extractFormula: it replaces, using the function metaParse, each metarepresentation of a bubble inside the metarepresentation of an assignment with the metarepresentation
of the corresponding term. Next, the variable SelEqs is instantiated using the function getLabelEqs, This function takes the metarepresentation of the label id and the metarepresentation of the module moduleG and returns the metarepresentation of the subset of equations in moduleG that are labelled id. Then, the variable NewGoal is instantiated, using the function applyApply, with the representation of the equality that results from applying any of the equations labelled id in module a, partially instantiated with the substitution subst, to the lefthand side of the equality t = t' at position pos. The definition of applyApply is as follows:
vars L R : Term .
var P : Position .
var EqC : Condition .
var Eqs : EquationSet .
var Match? : Substitution? .
eq applyApply(equality(Tl, T2), P, SB, none, Mod)
= equality(Tl, T2). ceq applyApply(equality(Tl, T2), P, SB,
(eq L = R [AS] . Eqs), Mod) = if Match? : : Substitution
then equality (replace (Tl, substituted, (SB ; Match?)), P), T2)
else applyApply(equality(Tl, T2), P, SB, Eqs, Mod) fi if Match? := metaMatch(Mod, substitute(L, SB),
getSubTerm(Tl, P), nil, 0) . ceq applyApply(equality(Tl, T2), P, SB,
(ceq L = R if EqC [AS] . Eqs), Mod) = if Match? : : Substitution
then equality (replace (Tl, substituted, (SB ; Math?)), P), T2)
else applyApply(equality(Tl, T2), P, SB, Eqs, Mod) fi . if Match? := metaMatch(Mod, substitute(L, SB),
getSubTerm(Tl, P), substituteCond(EqC, SB), 0) .
Notice how the built-in operation metaMatch is used to decide whether any of the equations labelled id in modules, partially instantiated with subs, can be applied to t at position pos. Finally, the variable NewGoals is instantiated with the result of appending, using the constructor goalSet, the value of NewGoal to the previous set of goals, from which G has been removed using the operation removeFrom,
Acknowledgements
I thank José Meseguer for many discussions and several key suggestions on how to exploit the reflective capabilities of Maude in the design and implementation of the ITP tool, I also thank Francisco Durân for his outstanding work on
Full Maude [10] on which the implementation of the ITP rests. Finally, I thank Miguel Palomino, Grigore Ro§u, and Juan Santa-Cruz for their helpful comments on the actual use of the ITP, and Narciso Marti-Oliet for his detailed comments on earlier drafts of this paper,
5 Conclusions
In this paper we have summarized the reflective capabilities of the Maude system [4,5], including both user-definable strategies and user-definable interfaces, and we have explained how they can be combined to implement, easily and efficiently, interactive metaprogramming applications in Maude, To illustrate the general methodology, we have described parts of the actual implementation of the ITP tool [3,2], an inductive theorem prover for equational specifications which has been fully implemented in Maude using the reflective capabilities of the system.
References
[1] Adel Bouhoula, Jean-Pierre Jouannaud, and José Meseguer. Specification and proof in membership equational logic. Theoretical Computer Science, 236:35132, 2000.
[2] Manuel Clavel. The ITP tool's home page. September 2003. The site contains the latest version of the ITP tool, the documentation currently available, and several examples of proof scripts of different complexity, http://www.ucm.es/info/dsip/clavel/itp/.
[3] Manuel Clavel. Reflection in Rewriting Logic: Metalogical Foundations and Metaprogramming Applications. CSLI Publications, 2000.
[4] Manuel Clavel, Francisco Durân, Steven Eker, Patrick Lincoln, Narciso Marti-Oliet, José Meseguer, and José F. Quesada. Maude: Specification and programming in rewriting logic. Theoretical Computer Science, 2002.
[5] Manuel Clavel, Francisco Durân, Steven Eker, Patrick Lincoln, Narciso Marti-Oliet, José Meseguer, and Carolyn Talcott. Maude 2.0 manual. June 2003. Manual distributed as documentation of the Maude system, http://maude.cs.uiuc.edu.
[6] Manuel Clavel, Francisco Durân, Steven Eker, and José Meseguer. Building equational proving tools by reflection in rewriting logic. In Kokichi Futatsugi, Ataru T. Nakagawa, and Tetsuo Tamai, editors, Cafe: An Industrial-Strength Algebraic Formal Method, pages 1-31. Elsevier, 2000. http://maude.csl.sri.com/papers.
[7] Manuel Clavel, Francisco Durân, Steven Eker, José Meseguer, and Mark-Oliver Stehr. Maude as a formal meta-tool. In Jeannette M. Wing, Jim Woodcock,
vy V L-li-1
and Jim Davies, editors, FM'99 — Formal Methods, World Congress on Formal Methods in the Development of Computing Systems, Toulouse, France, September 20-24, 1999 Proceedings, Volume II, volume 1709 of lecture Notes in Computer Science, pages 1684-1703. Springer-Verlag, 1999.
[8] Manuel Clavel and José Meseguer. Reflection in conditional rewriting logic. Theoretical Computer Science, 285(2):245-288, August 2002.
[9] Manuel Clavel, José Meseguer, and Miguel Palomino. Reflection in membership equational logic, many-sorted equational logic, Horn logic with equality, and rewriting logic. In F. Gadducci and U. Montanari, editors, Proc. Fourth International Workshop on Rewriting logic and its Applications, volume 71 of Electronic Notes in Theoretical Computer Science, pages 63-78. Elsevier, 2002.
[10] Francisco Durán. A Reflective Module Algebra with Applications to the Maude language. PhD thesis, Universidad de Málaga, Spain, June 1999. http://maude.csl.sri.com/papers.
[11] José Meseguer. Conditional rewriting logic as a unified model of concurrency. Theoretical Computer Science, 96(1):73—155, 1992.
[12] José Meseguer. Membership algebra as a logical framework for equational specification. In Francesco Parisi-Presicce, editor, Recent Trends in Algebraic Development Techniques, 12th International Workshop, WADT'97, Tarquinia, Italy, June 3-7, 1997, Selected Papers, volume 1376 of lecture Notes in Computer Science, pages 18-61. Springer-Verlag, 1998.
[13] José Meseguer. Research directions in rewriting logic. In U. Berger and H. Schwichtenberg, editors, Computational logic, Proceedings of the NATO Advanced Study Institute on Computational logic held in Marktoberdorf Germany, July 29 August 6, 1997, volume 165 of NATO ASI Series F: Computer and System,s Sciences, pages 347-398. Springer-Verlag, 1998.
[14] Arie van Deursen. Executable language Definitions. PhD thesis, University of Amsterdam, 1994.