[go: up one dir, main page]

Academia.eduAcademia.edu
TLP 3 (2): 189–221, March 2003. c 2003 Cambridge University Press DOI: 10.1017/S1471068402001527 Printed in the United Kingdom 189 Composing programs in a rewriting logic for declarative programming J. M. MOLINA-BRAVO and E. PIMENTEL Dpto. Lenguajes y Ciencias de la Computación, University of Málaga, Campus de Teatinos, 29071 Málaga, Spain (e-mail: {)jmmb, ernesto}@lcc.uma.es) Abstract Constructor-Based Conditional Rewriting Logic is a general framework for integrating first-order functional and logic programming which gives an algebraic semantics for nondeterministic functional-logic programs. In the context of this formalism, we introduce a simple notion of program module as an open program which can be extended together with several mechanisms to combine them. These mechanisms are based on a reduced set of operations. However, the high expressiveness of these operations enable us to model typical constructs for program modularization like hiding, export/import, genericity/instantiation, and inheritance in a simple way. We also deal with the semantic aspects of the proposal by introducing an immediate consequence operator, and studying several alternative semantics for a program module, based on this operator, in the line of logic programming: the operator itself, its least fixpoint (the least model of the module), the set of its pre-fixpoints (term models of the module), and some other variations in order to find a compositional and fully abstract semantics w.r.t. the set of operations and a natural notion of observability. KEYWORDS: functional-logic programming, modules, compositionality, full abstraction, semantics 1 Introduction Constructor-Based Conditional Rewriting Logic (CRWL)1 , presented in GonzálezMoreno et al. (1999), is a quite general approach to declarative programming that combines (first-order) functional and logic paradigms by means of the notion of (possibly) non deterministic lazy function. The basic idea is that both relations and deterministic lazy functions are particular cases of non-deterministic lazy functions. This approach retains the advantages of deterministic functions while adding the possibility of modeling non-deterministic functions by means of non-confluent constructor-based term rewriting systems, where a given term may be rewritten to constructor terms (possibly with variables) in more than one way. Here a fundamental notion is that of joinability: two terms a,b are joinable iff they can be rewritten to a common – but not necessarily unique – constructor term. In González-Moreno 1 CRWL must not be confused with the Rewriting Logic proposed in Meseguer (1992) as a unifying logical framework for concurrency. CRWL is a particular logic for dealing with indeterminism. 190 J. M. Molina-Bravo and E. Pimentel et al. (1999), CRWL is introduced with two equivalent proof calculi that govern deduction in this logic, an algebraic semantics for programs (theories) based on a freely generated model, and an operational semantics, based on a lazy narrowing calculus for solving goals, that is sound and complete w.r.t. the algebraic semantics. Modularity is a central issue in all programming paradigms motivated by the need of mastering the complexity inherent in large programs. Modularity related with algebraic specifications (which, to some extent, can be viewed as a sort of firstorder functional programming) has been extensively studied and all specification languages are extended for dealing with modules. In this field, a typical module consists of a body, an export interface, a list of imports and, possibly, a list of formal parameters, and typical operations with modules have to do with setting up hierarchical relationships between modules as the union of modules (with some constraints) and the application of a parameterized module to an actual module, and their semantics are given from a category-theoretic point of view (Goguen and Burstall, 1992; Ehrig and Mahr, 1990; Orejas, 1999). Nevertheless, there are other studies of modularity (Wirsing, 1990) with more flexible sets of operations semantically defined by means of operations on the sets of models, and also studies where modularity has been tackled with the tools of algebraic specifications, as in Bergstra et al. (1990), where an axiomatic specification is given for an algebra of non-parameterized modules and it is proved that each expression can be reduced to another one with, at most, an occurrence of the export (hiding) operator, and Durán (1999) where a constructive specification is given for an algebra of parameterized modules (without hiding) in Maude, and each expression is reduced to a flat module. In the logic programming field, modularity has been the objective of different proposals – see Bugliesi et al. (1994) for a survey about the subject – which basically have followed two different guidelines. One, focused on programming-in-the-large, extends logic programming with modular constructs as a meta-linguistic mechanism (Brogi and Turini, 1995) and gives semantics to modules with the aid of the immediate consequence operator. And the other one, focused on programmingin-the-small, enriches the theory of Horn clauses with new logical connectives for dealing with modules (Miller, 1986). In the first line, there is the work Brogi (1993) where an algebra of logic programs is studied. This algebra is based on three basic operations (union, intersection and encapsulation) defined at the semantic level and then translate to the syntactic level. It is proved that each program expression is equivalent to a, possibly infinite, flat program, and also a transformation is defined for mapping program expressions into finite programs by introducing system generated predicates and adding a hidden part to each program. Notions of module hiding some predicates and module importation are built up with the aid of the basic operations. On the other hand, in functional-logic programming we do not know any study of modularity semantically well founded. With this paper we have tried to contribute to filling this gap at least in the CRWL context. In this context, we deal with data constructors, as in logic programming, and functions defined by conditional rewrite rules, instead of predicates defined by Horn clauses, and we have proved (see section 3) that an operator, similar to the immediate consequence operator of logic Composing programs in CRWL 191 programs, can be defined to each CRWL-program and its least fixpoint coincides with the freely generated term-model given in González-Moreno et al. (1999). All this has motivated our decision of developing a study of programs structuring and modularity in CRWL, based on a meta-linguistic mechanism, similar to the one which appears in Brogi (1993). However, we have defined an algebra of program modules based on a different set of operations (union, deletion of a signature of function symbols, closure w.r.t. a signature and renaming) defined at the syntactical level in such a way that each program expression can be reduced to a, possibly infinite, flat program. With these operations we can model as well as notions of module which hides some functions and module importation, module parameterization, instantiation and inheritance with overriding. Also, we have introduced a notion of protected signature labeling symbols with module expressions, which allows to define structured modules and a representation morphism that maps each program expression into a finite structured module. We use protected signature, not only for hiding functions as is done in Brogi (1993) for predicates, but also for hiding data constructors. An important aspect to be considered when a language is extended for modular programming is the sound integration of the behavior of the modular operations into the semantics of the language. The compositionality of the semantics of a programming language is particularly relevant when modularity is involved. In fact, one of the most critical aspects in modular systems is the possibility of making a separate compilation of modules, and this can only be made in the presence of this property. On the other hand, full abstraction measures the implementation details of the semantics of a programming language. A non-fully abstract semantics makes the intended meaning of a program to include non relevant aspects, which do not depend on the behavior of the program but on a particular ‘implementation’. In some sense, full abstraction can be seen as the complementary property of compositionality, and the adequacy of a semantics is established when both full abstraction and compositionality are obtained. In Brogi (1993), the semantics of a program is given by its immediate consequence operator which captures the information concerning possible compositions, this semantics is compositional by construction and it is proved that also is fully abstract w.r.t. a notion of observable behavior given by the success sets of programs (least fixpoints of their immediate consequence operators). In CRWL-programming, the semantics given by the immediate consequence operator is compositional but not fully abstract when we take the freely generated term-model as observable behavior. For this reason, we study several alternative semantics to find one that is compositional and fully abstract. We are confident that our work could serve as a reference to other studies of modularity in functional-logic programming, and, although we are focused on the modular aspects of the semantics, the results obtained in this paper, as well as the study of a wide range of other issues concerning semantics, makes the current work also relevant from a purely semantic point of view, in the context of rewriting logic-based programming languages. The approach to modularity in CRWL-programming, that we present here, substantially extends a previous one in Molina-Bravo and Pimentel (1997) with a more elaborate notion of program 192 J. M. Molina-Bravo and E. Pimentel module and a new operation (renaming) that makes clear the difference between importation and instantiation, and a more recent one (Molina-Bravo, 2000) with the notions of structured module and module representation that allows to express closed modules by means of a finite number of rules and also to deal with local constructor symbols. For space reasons we do not include the proofs of the results; they are available at http://arxiv.crg/abs/cs/0203006. The paper is organized as follows: in the next section we introduce the basic features of the CRWL approach to functional-logic programming and its modeltheoretic semantics – for a detailed presentation we refer to González-Moreno et al. (1999). In section 3 we introduce an immediate consequence operator TR , for each CRWL-program R, and a fixpoint semantics that matches the free term-model MR proposed in González-Moreno et al. (1999). In section 4 we define a notion of (plain) module together with a reduced set of operations on program modules, and we express some modular constructions with these operations. In section 5 we give the T-semantics that characterizes the meaning of a CRWL-program when we consider composition of programs and prove that this semantics is compositional but not fully abstract w.r.t. the set of operations, taking MR as the observable behavior of a program R. In section 6 we introduce a fully abstract semantics by denoting a program module with the set of all its consistent term-models (pre-fixpoints of TR ); but this semantics is not compositional for the deletion of a signature. In section 7, we obtain a compositional and fully abstract semantics as an indexed family of sets of consistent term-models for single functions. In section 8, we introduce the notion of structured module as a finite representation of expressions made up from finite plain modules that allows the hiding of constructor symbols. Finally we present a discussion and some conclusions. 2 CRWL for declarative programming A signature with constructors is a pair Σ = (DSΣ , FSΣ ), where DSΣ and FSΣ are countable disjoint sets of strings h/n with n ∈ N. Each c such that c/n ∈ DSΣ is a constructor symbol with arity n and each f such that f/n ∈ FSΣ is a (defined) function symbol with arity n. The set of all constructor symbols and the set of all function symbols with arity n are denoted by DSΣn and FSΣn , respectively. Given a signature (with constructors) Σ and a set V of variable symbols, disjoint from all of the sets DSΣn and FSΣn , we define Σ-terms as follows: each symbol in V and each symbol in DSΣ0 ∪ FSΣ0 is a Σ-term, and for each h ∈ DSΣn ∪ FSΣn and t1 , . . . , tn terms, h(t1 , . . . , tn ) is a term. TermΣ is the set of all Σ-terms and CTermΣ the subset of those Σ-terms (called constructor terms) built up only with symbols in DSΣ and V. To cope with partial definition we add a new 0-arity constructor ⊥ to each signature Σ obtaining an extended signature Σ⊥ whose terms are called partial Σ-terms. When the signature Σ is clear, we will omit explicit mention of it, and we will write Term and CTerm (or Term⊥ and CTerm⊥ for Σ⊥ ) respectively. Following the approach to nondeterminism in Hussmann (1993), we only consider C-substitutions θ: V → CTerm. These mappings have natural extensions θ: Term → Term, also noted as θ, defined in the usual way, and the result of applying θ to the term t is written tθ. Analogously, Composing programs in CRWL 193 we define partial C-substitutions as mappings θ: V → CTerm⊥ . The set of all C-substitutions (partial C-substitutions) is written CSubst (CSubst⊥ ). A signature morphism ρ: Σ → Σ′ from a signature Σ = (DSΣ , FSΣ ) to a signature Σ′ = (DSΣ′ , FSΣ′ ) consists of two mappings, that we denote with the same symbol ρ: DSΣ → DSΣ′ and ρ: FSΣ → FSΣ′ , that map strings h/n into strings h′ /n. By abuse of notation we will denote h′ = ρ(h). This allows us to define a mapping ρ: TermΣ⊥ → TermΣ′ ⊥ as ρ(h) =def h, for h ∈ V ∪ {⊥} ∪ DSΣ0 ∪ FSΣ0 ; ρ(h(t)) =def ρ(h)(ρ(t1 ), . . . , ρ(tn )), for h ∈ DSΣn ∪ FSΣn , n > 0. ρ(h) =def h, for h ∈ V ∪ {⊥} ∪ DSΣ0 ∪ FSΣ0 , and ρ(h(t)) =def ρ(h)ρ(t1 ), . . . , ρ(tn )), for h ∈ DSΣn ∪ FSΣn and n > 0. We will consider signature morphisms ρ: Σ → Σ such that ρ(h/n) = h/n for every string h/n in DSΣ . Such morphisms will be called function symbol renamings. Given a signature Σ and a set V of variable symbols, there are two kinds of atomic CRWL-formulas for a, b ∈ Term⊥ , reduction statements a → b, with the intended meaning “a can be reduced to b,” and joinability statements a ⊲⊳ b, with the intended meaning “a and b can be reduced to a common value in CTerm”. Terms t ∈ CTerm are intended to represent totally defined values whereas terms t ∈ CTerm⊥ represent partially defined values — to model the behavior of non-strict functions. Reduction statements a → t with t ∈ CTerm⊥ , called approximation statements, have the intended meaning that t approximates a possible value of a, whereas a → t with t ∈ CTerm have the intended meaning that t represents a possible value of a – an expression may denote several values capturing the behavior of non-deterministic functions. Substitutions θ ∈ CSubst⊥ and signature morphisms ρ: Σ → Σ′ apply to formulas in the obvious way. A CRWL-program is a CRWL-theory R defined as a signature Σ together with a set of conditional rewrite rules of the general form f(t) → r ⇐ C, where f(t) is the left-hand side (lhs), r the right-hand side (rhs), C the condition of the rule, f is a function symbol with arity n > 0, and C consists of finitely many (possibly zero) joinability statements between fully defined terms (with no occurrence of ⊥). When n > 0, t is a linear n-tuple (i.e. without repeated variables) of fully defined constructor terms ti ∈ CTerm. When n = 0 rules take the simpler form f → r ⇐ C. Formal derivation of CRWL-statements from a given program R is governed by two equivalent calculi (see González-Moreno et al. (1999)). We present here the so-called Goal-Oriented Proof Calculus (GPC), which focuses on top-down proofs of reduction and joinability statements: (Bo) e → ⊥, for e ∈ Term⊥ ; (RR) e → e, for e ∈ V ∪ DS 0 ; (DS) e1 → t1 . . . en → tn , c(e) → c(t) (OR) (Jo) e1 → t1 . . . en → tn C r → t , f(e) → t a→t b→t , a ⊲⊳ b for c ∈ DS n and ei , ti ∈ Term⊥ ; if (f(t) → r ⇐ C) ∈ [R]⊥ and t 6≡ ⊥; if t ∈ CTerm and a, b ∈ Term⊥ ; where [R]⊥ = {(l → r ⇐ C)θ | (l → r ⇐ C) ∈ R, θ ∈ CSubst⊥ } is the set of possibly partial constructor instances of rewrite rules and C-substitutions apply to rules in 194 J. M. Molina-Bravo and E. Pimentel the obvious way. Rule (Bo) shows that a CRWL-reduction is related to the idea of approximation, and rule (OR) states that only constructor instances of rewrite rules are allowed in this calculus reflecting the so-called ‘call-time-choice’ (Hussmann, 1993) for non-determinism (values of arguments for functions are chosen before the call is made). When a reduction or joinability statement ϕ is derivable from a program R we write R ⊢CRW L ϕ and we say that ϕ is provable in R. Goals for a program R are finite conjunctions of atomic formulas, and solutions are Csubstitutions that make goals derivable. In González-Moreno et al. (1999), a sound and complete lazy narrowing calculus for goal-solving can be found. We interpret CRWL-programs over algebraic structures consisting of posets with bottom as carriers (i.e. sets D with a partial order ⊑D and a least element ⊥D ), whose elements are thought of as finite approximations of possibly infinite values in the poset’s ideal completion (Möller, 1985), and monotonic mappings from elements to cones (non-empty subsets of a poset with bottom, downclosed w.r.t. the partial order of the poset) as function symbol denotations reflecting possible non-determinism. Such a mapping f: D → C(E) – where D, E are posets with bottom, and C(E) is the set of cones of E – can be extended to a monotonic mapping f̂: C(D) → C(E), S defined by f̂(C) =def u∈C f(u) and also noted f by abuse of notation. In particular, deterministic function symbols are represented by mappings f: D → I(E) computing directed cones or ideals (i.e., cones C such that for all x, y ∈ C there exists z ∈ C with x ⊑ z and y ⊑ z) where I(E) is the set of ideals of E. These mappings become continuous mappings between algebraic cpos after performing the ideal completion (for a comprehensive exposition of these notions we refer to Abramsky and Jung (1994)). These ideas are behind the notion of CRWL-algebra. Given a signature Σ and a set V of variable symbols, a CRWL-algebra of signature Σ is an algebraic structure A = (DA , {cA }c∈DSΣ , {f A }f∈FSΣ ) where the carrier DA n is a poset with bottom ⊥A , f A is a monotonic mapping DA → C(DA ) for each n → I(DA ) for each c ∈ DSΣn . Both f A f ∈ FSΣn and cA is a monotonic mapping DA and cA reduce to cones when n = 0. To ensure preservation of finite and maximal elements in the ideal completion, we require for all u1 , . . . , un ∈ DA that there exists v ∈ DA such that cA (u1 , . . . , un ) = hvi, where hvi is the ideal generated by v (i.e. the set {d ∈ DA | d ⊑ v}), and if all ui are maximal (totally defined) then v must also be maximal. The class of all CRWL-algebras of signature Σ is denoted by AlgΣ . We are specially interested in CRWL-term algebras, which are CRWL-algebras with carrier CTerm⊥ , ordered by the approximation ordering ‘⊑’, defined as the least partial ordering satisfying the following properties: (a) (b) ⊥ ⊑ t, c(s) ⊑ c(t) ∀t ∈ CTerm⊥ ; if si ⊑ ti , i = 1, . . . , n, for c ∈ DSΣn , n > 0; and fixed interpretation for constructor symbols: cA = hci, for all c ∈ DSΣ0 , and cA (t) = hc(t)i, for all c ∈ DSΣn and n > 0. Therefore, two CRWL-term algebras of the same signature Σ will only differ in their interpretations for the function symbols of Σ. As a consequence of the above definition, for s, t ∈ CTerm⊥ , s ⊑ t implies s = ⊥ or s = c(s) and t = c(t) for some c ∈ DSΣn and n > 0 with each component si ⊑ ti . Also, for s, t ∈ CTerm⊥ , s ⊑ t is equivalent to ⊢CRWL t → s. It can be proved, Composing programs in CRWL 195 by induction, that every θ ∈ CSubst⊥ is a monotonic mapping from CTerm⊥ to CTerm⊥ , that is: s ⊑ t ⇒ sθ ⊑ tθ, for all s, t ∈ CTerm⊥ . A valuation over a structure A ∈ AlgΣ is any mapping η: V → DA . η is totally defined when η(X) is maximal for all X ∈ V. Val(A) is the set of all valuations over A and DefVal(A) the set of all totally defined valuations. Given a valuation η we can evaluate each partial Σ-term in A as follows: [[ ⊥ ]] A η [[ X ]] A η [[ c ]] A η [[ h(e) ]] A η =def =def =def =def h⊥A i, hη(X)i, ∀X ∈ V; cA , ∀c ∈ DSΣ0 ∪ FSΣ0 ; A n n ĥA ( [[ e1 ]] A η , . . . , [[ en ]] η ), ∀h ∈ DSΣ ∪ FSΣ , n > 0. In this way each partial Σ-term is evaluated to a cone. For each CRWL-algebra A, every η ∈ Val(A), and e ∈ Term⊥ , the following properties are proved in González-Moreno et al. (1999): 1. [[ e ]] A η ∈ C(DA ). 2. [[ e ]] A η ∈ I(DA ), if e is only built from deterministic functions (i.e. function symbols interpreted by ideal valued functions). 3. [[ e ]] A η = hvi for some v ∈ DA , if e ∈ CTerm⊥ . Moreover, when e ∈ CTerm and η ∈ DefVal(A), v is maximal. A 4. (Substitution Lemma) [[ eθ ]] A η = [[ e ]] ρ , for θ ∈ CSubst⊥ , where ρ is the uniquely determined valuation that satisfies hρ(X)i = [[ Xθ ]] A η , for all X ∈ V. From these results and taking into account that each substitution is equivalent to a valuation over any CRWL-term algebra, we have the following complementary results for term algebras: Proposition 1 For each CRWL-term algebra A and every η ∈ Val(A) we have: 1. [[ t ]] A η = htηi for every t ∈ CTerm⊥ ; A n n 2. [[ h(t) ]] A η = h (tη) for all h ∈ DSΣ ∪ FSΣ , n > 0, and t1 , . . . , tn ∈ CTerm⊥ ; A A 3. [[ eθ ]] η = [[ e ]] θη for all e ∈ Term⊥ and θ ∈ CSubst⊥ , where θη represents the function composition η ◦ θ. Models in CRWL are introduced from the following notion of satisfiability: • A satisfies a reduction statement a → b under a valuation η ∈ Val(DA ), or A A |=η (a → b), iff [[ a ]] A η ⊇ [[ b ]] η . • A satisfies a joinability statement a ⊲⊳ b under a valuation η ∈ Val(DA ), or A A |=η (a ⊲⊳ b), iff [[ a ]] A η ∩ [[ b ]] η contains a maximal element in DA . • A satisfies a rule l → r ⇐ C, or A |= (l → r ⇐ C), iff A |=η C implies A |=η (l → r), for every valuation η ∈ Val(DA ). • A is a model of a program R, i.e., A |= R, iff A satisfies all rules in R. CRWL-provability is sound and complete w.r.t. this model-theoretic semantics when we consider totally defined valuations only. In González-Moreno et al. (1999) it is proved that for any program R and any approximation or joinability statement ϕ, R ⊢CRW L ϕ is equivatent to A |=η ϕ, for every A model of R and η ∈ DefVal(DA ). 196 J. M. Molina-Bravo and E. Pimentel This result is achieved with the help of a CRWL-term algebra MR characterized by the following interpretation for any defined function symbol f ∈ FSΣn , n > 0, f MR (t) =def {r ∈ CTerm⊥ | R ⊢CRW L f(t) → r}. MR is such that R ⊢CRW L ϕ ⇔ MR |=id ϕ for any approximation or joinability statement ϕ. According to this result, MR is taken as the canonical model of the program R. Also, in González-Moreno et al. (1999), it is proved that this model is freely generated by V in the category of all models of R. This is the model-theoretical semantics of the program R. Given a signature Σ and a function symbol renaming ρ: Σ → Σ, for each CRWLterm algebra A = (CTerm⊥ , {cA }c∈DSΣ , {f A }f∈FSΣ ) of this signature we can define another CRWL-term algebra Aρ = (CTerm⊥ , {cAρ }c∈DSΣ , {f Aρ }f∈FSΣ ), such that f Aρ = ρ(f)A . The relation between evaluation and satisfaction in A and evaluation and satisfaction in Aρ is stated by the following proposition. Proposition 2 Given a signature Σ, for every CRWL-term algebra A of this signature, every function symbol renaming ρ: Σ → Σ, and all θ ∈ CSubst⊥ , we have 1. (ρ(t))θ = ρ(tθ), for all t ∈ Term⊥ . Aρ 2. [[ ρ(t) ]] A θ = [[ t ]] θ , for all t ∈ Term⊥ . 3. A |=θ ρ(ϕ) ⇔ Aρ |=θ ϕ, for any reduction or joinability statement ϕ. 3 Fixpoint semantics In this section we prove, for every CRWL-program R, that MR is the least fixpoint of an operator defined over CRWL-term algebras. The approach we use here is similar to that applied in the field of logic programming (Apt, 1990). However, the notion of interpretation, and the corresponding mathematical aspects, have to be reformulated in the context of CRWL-term algebras. This approach has been also used in González-Moreno (1994) in the context of a previous formalism to model functional-logic programming. However, this work does not deal with some relevant aspects (e.g. non-determinism) of the CRWL-programming version we are considering here. Let TAlgΣ be the set of all CRWL-term algebras of a signature Σ associated to a CRWL-program R. We can define the relationship A ⊑ B, between two algebras A, B ∈ TAlgΣ , as f A (t) ⊆ f B (t) for all f ∈ FSΣn , when n > 0, and f A ⊆ f B , when n = 0. This relationship is obviously a partial ordering and (TAlgΣ , ⊑) is a poset. This poset has a bottom ⊥Σ and a top ⊤Σ characterized by f ⊥Σ (t) = h⊥i and f ⊤Σ (t) = CTerm⊥ , respectively, for each f ∈ FSΣn and n > 0. S Given a subset S ⊆ TAlgΣ , the following definitions: f ⊔S (t) =def A∈S f A (t), and T f ⊓S (t) =def A∈S f A (t), for each f ∈ FSΣn and n > 0, characterize two CRWL-term algebras, ⊔S and ⊓S respectively, because the union and intersection of any number of cones are cones also, and the resulting functions in the above definitions are obviously monotonic if f A is monotonic for all A ∈ S. Clearly, ⊔S and ⊓S are the Composing programs in CRWL 197 least upper bound and the greatest lower bound of S, respectively. So, (TAlgΣ , ⊑) is a complete lattice. Valuations (substitutions) of terms in term algebras can be considered continuous mappings from algebras to cones in the sense given by the following lemma. Lemma 1 (Continuity of valuations in TAlgΣ ) For each term e ∈ Term⊥ and each substitution θ ∈ CSubst⊥ B 1. A ⊑ B ⇒ [[ e ]] A θ ⊆ [[ e ]] θ , for A, B ∈ TAlgΣ . S A ⊔D 2. [[ e ]] θ = A∈D [[ e ]] θ , for all directed subsets D ⊆ TAlgΣ . Another interesting result relates satisfiability of joinability statements in the least upper bound of a directed set of term algebras with satisfiability in, at least, one of the algebras of the set. Lemma 2 Let C be a finite set of joinability statements and D a directed subset of TAlgΣ , then ⊔D |=θ C implies that there exists A ∈ D such that A |=θ C. Given a CRWL-program R, with a signature Σ, we can define an algebra transformer TR : TAlgΣ → TAlgΣ , similar to the immediate consequences operator used in logic programming, by fixing the interpretation of each function symbol f ∈ FSΣn , in a transformed algebra TR (A), as the result of one step applications of reduction statements corresponding to instances – not necessarily ground – of those rules of R, defining f, satisfied in A. We formalize this idea defining, for each f ∈ FSΣn , n > 0, f TR (A) (t) =def {t | ∃(f(s) → r ⇐ C) ∈ [R]⊥ , si ⊑ ti , A |=id C, t ∈ [[ r ]] A id } ∪ {⊥}, that is basically a union of cones [[ r ]] A id . This definition corresponds to a monotonic mapping because all rule instances (f(s) → r ⇐ C) ∈ [R]⊥ , applicable to arguments t′ are also applicable to arguments t such that t′i ⊑ ti , for i = 1, . . . , n, and so the corresponding interpretation characterizes a CRWL-term algebra. From this definition of TR we can derive the continuity of the operator in TAlgΣ . Proposition 3 For each program R its associated operator TR is continuous. Thus, TR has a least fixpoint FR given by ⊔AR (that is also the least prefixpoint), where AR is the chain of CRWL-term algebras Ai , i ∈ N, such that A0 = ⊥Σ ⊑ · · · ⊑ Ai+1 = TR (Ai ) ⊑ · · ·. FR is also denoted as TR ω (⊥Σ ) (see Abramsky and Jung (1994)). To prove that FR coincides with MR we need two lemmata, one characterizing the set of term models and other relating CRWLprovability with AR satisfiability. Lemma 3 (Model characterization) Given a program R, M is a term model for R iff TR (M) ⊑ M Lemma 4 Given e ∈ Term⊥ and t ∈ CTerm⊥ , we have that R ⊢CRW L e → t implies Ai |=id e → t for some Ai ∈ AR . 198 J. M. Molina-Bravo and E. Pimentel From the above results we obtain the following proposition. Proposition 4 For every program R, MR is the least fixpoint (and the least pre-fixpoint) of TR . Thus, if we consider the meaning of a program R as the least fixpoint of its associated transformer TR , then this fixpoint semantics coincides with the modeltheoretic semantics as it happens in logic programming. In fact, this semantics would correspond to the C-semantics in Falaschi et al. (1993). Definition 1 (Least model semantics) For each program R we define its least model semantics as: {[ R ]}LM =def MR . 4 An algebra of CRWL-program modules For designing large programs it is convenient to separate the whole task into subtasks of manageable size and construct programs in a structured fashion by combining and modifying smaller programs. This idea has been extended to many programming languages giving rise to different notions of program module, each one being attached to a programming paradigm. In CRWL-programming we are going to follow an approach close to that developed in Brogi (1993) for logic programming, where modules are open programs in the sense that function definitions in a module can be completed with definitions for the same functions in other modules. We will consider a global signature with bottom Σ⊥ = (DSΣ⊥ , FSΣ⊥ ) and a countable set V of variable symbols and will construct modules and module expressions with symbols of these sets. Σ⊥ and V will characterize the environment where modules are written. Also we will consider all constructor symbols in DSΣ⊥ common to all program modules as it is usual in other proposals of modularity for declarative programming, like Brogi et al. (1994) and Orejas et al. (1997), where compositionality and full abstraction are dealt with. With this decision we give up any possibility of data abstraction and the only contribution of a program module to the environment will be a set of (definition) rules for a subsignature of function symbols. We will take this subsignature to denote the exportable resources of the module, and the set of rules as its body. In a program module, function symbols may appear – in the rhs of a rule – with no definition rule in this module. Although it may be assumed that all function symbols are defined in each program module by assuming an implicit rule f(t) → ⊥ for each function symbol f with no definition rule, these symbols will be assumed to be provided by other modules and they will be taken to denote the resources that have to be imported. They will be the parameters of the module. From these considerations we propose the following definition for the notion of module in CRWL-programming Definition 2 (Module) A module in CRWL-programming is a tuple < σp , σe , R > where R is a set of program rules f(t) → r ⇐ C (r 6= ⊥), σe is the (exported) signature of function symbols with a definition rule in R, σp is the (parameter) signature of those function symbols with no definition rule in R that appear in any rule (i.e. they are invoked but not defined). Composing programs in CRWL 199 R is the body of the module and (σp , σe ) its interface. The interface of a module could be inferred from its body if one knows which are the constructor symbols. However, as we consider all constructor symbols common to all program modules, we do not include an explicit declaration of these symbols in any module and have to make explicit parameter signatures in order to distinguish between function and constructor symbols. In this way, every symbol not occurring in σe nor σp will be a constructor symbol. Next, we have an example of a module definition. Example 3 This example shows a module for constructing ordered lists of natural numbers with functions for inserting elements, checking the type of an element, and compare natural numbers. OrdNatList = < {}, % Parameter signature {isnat/1, leq/2, insert/2}, % Exported signature { isnat(zero) -> true. isnat(succ(X)) -> isnat(X). leq(zero,zero) -> true. leq(zero,succ(X)) -> isnat(X). leq(succ(X),zero) -> false <= isnat(X) >< true. leq(succ(X),succ(Y)) -> leq(X,Y). insert(X,[]) -> [X] <= isnat(X) >< true. insert(X,[Y|Ys]) -> [X|[Y|Ys]] <= leq(X,Y) >< true. insert(X,[Y|Ys]) -> [Y|insert(X,Ys)] <= leq(X,Y) >< false.}> In this module the parameter signature is empty, and symbols like zero/0, succ/1, []/0, [_|_]/2 with no definition rule are considered constructor symbols, because they are not included in the parameter signature (and obviously because they occur in arguments of left-hand sides). We write PMod(Σ⊥ ) for the class of all program modules which can be defined with a signature Σ⊥ , SubSig(Σ⊥ ) for the set of all subsignatures of a signature Σ⊥ , and Prg(Σ⊥ ) for the class of all sets of rules (programs) which can be defined with Σ⊥ . On PMod(Σ⊥ ) we define three projections: • par: PMod(Σ⊥ ) → SubSig(Σ⊥ ) such that par(< σp , σe , R >) = σp , • exp: PMod(Σ⊥ ) → SubSig(Σ⊥ ) such that exp(< σp , σe , R >) = σe , and • rl : PMod(Σ⊥ ) → Prg(Σ⊥ ) such that rl (< σp , σe , R >) = R, which give respectively the parameter signature, the exported signature, and the body of a module. 4.1 Basic operations on modules In this section we present a set of basic operations with modules that allows us to express typical features of modularization techniques such as information hiding/abstraction, import/export relationships and inheritance related to function symbols as is done in Brogi (1993), but our set of operations is different and we give syntactic definitions for it. We use three operations: union of programs, closure 200 J. M. Molina-Bravo and E. Pimentel w.r.t. a signature and deletion of a signature, that are sufficient to express the most extended ways of composing modules and their relationships, and we do not need the intersection of programs, used in Brogi (1993) to model hiding, because we directly deal with signatures in the closure. To give more flexibility in expressing importation and instantiation, we also include a renaming operation. We define our operations in such a way that all module expressions can be reduced to a flat module < σp , σe , R > – where R could be an infinite set of rules. This is something like a presentation semantics (Wirsing, 1990). First we define the union of two modules as the module obtained as the simple union of signatures and rules. Definition 4 (Union) Given two modules P1 =< σp1 , σe1 , R1 > and P2 =< σp2 , σe2 , R2 >, their union P1 ∪P2 is defined as the module < (σp1 ∪ σp2 ) \ (σe1 ∪ σe2 ), σe1 ∪ σe2 , R1 ∪ R2 >. Each argument in this operation is considered an open program that can be extended or completed with the other argument possibly with additional rules for its exported function symbols. Example 5 Let us consider the following module with a function to give change for an amount of money. Values for coins are provided by the non-deterministic function coin/0, whereas getcoin/1 gives different possibilities to get a coin for a fixed amount. Finally, the function change/1 returns a list with the coins corresponding to the change. In this example, we are assuming a predefined arithmetic with the usual notation for natural numbers. This was not the case in Example 3. MoneyChange = < {_=<_/2, _-_/2}, {coin/0,getcoin/1,change/1}, { coin -> 1. coin -> 5. coin -> 10. getcoin(N) -> C <= coin >< C, C =< N >< true. change(0) -> []. change(N) -> [C|change(N-C)] <= getcoin(N) >< C. } > We can extend this module with another module for providing new coins: NewCoins = <{},{coin/0},{coin -> 15. coin -> 20.}> simply by joining them to obtain MoneyChange ∪ NewCoins = < {_=<_/2, _-_/2}, {coin/0,getcoin/1,change/1}, { coin -> 1. coin -> 5. coin -> 10. coin -> 15. coin -> 20. getcoin(N) -> C <= coin >< C, C =< N >< true. change(0) -> []. change(N) -> [C|change(N-C)] <= getcoin(N) >< C. } > Union of modules is idempotent, associative, commutative, and there exists a null element: the module O =< σo , σo , ∅ >, where σo is the empty signature of function symbols, representing the module with no rule. Composing programs in CRWL 201 Proposition 5 The union of modules has the following properties: 1. 2. 3. 4. P ∪ O = P, for every module P. P ∪ P = P, for every module P. (P ∪ P1 ) ∪ P2 = P ∪ (P1 ∪ P2 ), for all modules P, P1 and P2 . P1 ∪ P2 = P2 ∪ P1 , for all modules P1 and P2 . The second operation is the closure of a module w.r.t. a given signature σ. This operation makes accessible the signature σ in an extensional way (i.e. only provable approximations can be used) and hides the rest. To define this operation, we need to introduce the notion of canonical rewrite rule. Definition 6 (Canonical rewrite rule) Given a term f(t), with f ∈ FSΣn and each ti ∈ CTerm⊥ , and r ∈ CTerm⊥ , we define the canonical rewrite rule crr(f(t), r) which reduces f(t) to r, as the rule ′ f(t ) → r ⇐ C, constructed by substituting in t each occurrence of a repeated variable X or ⊥ with a fresh variable Y and adding in C a joinability statement X ⊲⊳ Y for each occurrence of a repeated variable X, and a statement X ⊲⊳ X for each variable X in r and each variable with only one occurrence in t. ′ In this way we obtain a program rule (with t linear and each t′i ∈ CTerm) from which f(t) → r can be proved, because for θt ∈ CSubst⊥ such that θt (Y ) = X for each fresh variable Y that substitutes an occurrence of X in t, θt (Y ) = ⊥ for each fresh variable Y that substitutes an occurrence of ⊥, and θt (X) = X for all other ′ variables, Cθt always can be proved and (f(t ) → r)θt is f(t) → r. Example 7 The canonical rewrite rule which reduces f(⊥, b(X, Y ), X) to a(X, Z) is: f(V , b(X, Y ), X1) → a(X, Z) ⇐ {X1 ⊲⊳ X, Y ⊲⊳ Y , Z ⊲⊳ Z}, and the associated substitution θt is such that θt (X1) = X, θt (V ) = ⊥, and θt (W ) = W for all other variables W . In this case Cθt = {X ⊲⊳ X, Y ⊲⊳ Y , Z ⊲⊳ Z} and all these joinability statements can be trivially derived from (RR) and (Jo), and therefore f(⊥, b(X, Y ), X) → a(X, Z) by the (OR) rule. Now, we can define the closure of a module as follows. Definition 8 (Closure w.r.t. a signature) σ Given a module P =< σp , σe , R >, its closure P w.r.t. a signature of function symbols σ is defined as the module: < σo , σe′ , {crr(f(t), r) | f/n ∈ σ, r ∈ CTerm⊥ , r 6= ⊥, R ⊢CRW L f(t) → r} >, where σo denotes the empty signature of function symbols, ti ∈ CTerm⊥ for each component of the tuple t, and σe′ is the corresponding exported signature. The closure of a module is a module with a possibly infinite set of rules (although the exported signature is always finite) equivalent to the union of the graphs in MP of all functions defined in P and contained in σ. Note that σe′ ⊆ σe ∩ σ because 202 J. M. Molina-Bravo and E. Pimentel a function in σe ∩ σ that depends on functions in the parameter signature could remain with no definition rule – or with the only rule f(t) → ⊥ – after closing the σe module. As a syntactic simplification we will write P instead of P for each module P =< σp , σe , R >. Example 9 Let us consider the following module about week days, where two functions are defined to get the next day and the day before of a given day. WeekDays = < {}, {next/1,before/1}, { next(mo) -> tu. next(tu) -> we. next(th) -> fr. next(fr) -> sa. next(su) -> mo. before(X) -> Y <= next(Y) >< X. } next(we) -> th. next(sa) -> su. > The closure of this module w.r.t. its whole exported signature is the module WeekDays = < {}, {next/1,before/1}, { next(mo) -> tu. next(tu) -> we. next(we) -> th. next(th) -> fr. next(fr) -> sa. next(sa) -> su. next(su) -> mo. before(tu) -> mo. before(we) -> tu. before(th) -> we. before(fr) -> th. before(sa) -> fr. before(su) -> sa. before(mo) -> su. } > Closure w.r.t. a signature is in some way the counterpart of the encapsulation operation ‘∗’ in Brogi (1993), but it is more general because it has a twofold effect: hiding all rules in the module and restricting the visible signature, so we need no intersection of modules – as is needed in Brogi (1993) – to restrict visibility in a closed module. Variables and bottom can appear in the rules of a closed module, but no functions in the parameter signature. Proposition 6 Closure of modules has the following properties, where σ, σ1 and σ2 are signatures of function symbols, 1. 2. 3. 4. 5. σ P = O, for every module P and every signature σ such that σ ∩ exp(P) = σo . σ O = O, for every signature σ and the null module O. σ1 ∪σ2 σ1 σ2 P = P ∪ P , for every module P and signatures σ1 , σ2 . σ1 σ2 σ1 ∩σ2 σ2 σ1 P =P = P , for every module P and signatures σ1 , σ2 . σ σ σ P1 ∪ P2 = P1 ∪ P2 , for modules P1 and P2 defining disjoint signatures and such that neither P1 nor P2 use the signature defined in the other module. Our third operation is the deletion of a signature in a module. Definition 10 (Deletion of a signature) Given a module P =< σp , σe , R >, the deletion in P of a signature of function symbols σ produces the module P \ σ =def < σp′ , σe \ σ, R \ σ >, where R \ σ denotes the set of those rules in R defining function symbols not appearing in σ, and σp′ denotes the corresponding parameter signature. Composing programs in CRWL 203 We do not give an explicit expression for par(P \ σ) in terms of par(P) because new parameters can appear and old ones can disappear with the deletion of rules in rl (P). However, par(P \ σ) ⊆ σp ∪ (σe ∩ σ) is satisfied. Example 11 In the module OrdNatList of Example 3 we can delete or abstract the signature {isnat/1,leq/2} to obtain the following parameterized module OrdNatList\{isnat/1,leq/2} = < {isnat/1,leq/2}, {insert/2}, { insert(X,[]) -> [X] <= isnat(X) >< true. insert(X,[Y|Ys]) -> [X|[Y|Ys]] <= leq(X,Y) >< true. insert(X,[Y|Ys]) -> [Y|insert(X,Ys)] <= leq(X,Y) >< false. } > The resulting module is now parameterized by the two symbol functions isnat/1 and leq/2, whereas only the function insert/2 is exported. This operation recalls the undefine clause in the object-oriented language Eiffel, and we will use it (combined with the union) to perform inheritance with overriding. Note the differences between the deletion of a signature and the closure w.r.t. a signature. The former operation removes rules defining function symbols in the signature – but not those rules containing invocations in their rhs or condition – whereas the latter only hides the definitions of the functions in the signature, but maintains their consequences – hiding all other functions. Proposition 7 The deletion of a signature (of function symbols) in a module has the following properties, where σ, σ1 and σ2 are signatures of function symbols, 1. 2. 3. 4. 5. 6. P \ σ = O, for every module P and every σ such that exp(P) ⊆ σ. P \ σ = P, for every module P and every σ such that exp(P) ∩ σ = σo . (P \ σ1 ) \ σ2 = P \ (σ1 ∪ σ2 ) = (P \ σ2 ) \ σ1 , for all modules P and σ1 , σ2 . (P1 ∪ P2 ) \ σ = (P1 \ σ) ∪ (P2 \ σ), for all modules P1 , P2 and signatures σ. σ1 (σ1 \σ2 ) , for all modules P and signatures σ1 , σ2 . (P ) \ σ2 = P σ P = P \ (σe \ σ), for a module P, with exported signature σe , and all σ. Finally, we introduce a renaming operation that allows us to change function symbols with other function symbols of the same arity, in the global signature Σ⊥ . Therefore, given a module P and a function symbols renaming ρ, we define the renaming of P by ρ as a new module ρ(P) where rules are conveniently renamed. The following definition formalizes this idea. Definition 12 (Renaming) Given a module P =< σp , σe , R > and a function symbol renaming ρ, P renamed by ρ is the module ρ(P) =def < ρ∗ (σp ) \ ρ∗ (σe ), ρ∗ (σe ), ρ∗ (R) >, where ρ∗ (σ) is the signature resulting from applying ρ to all symbols in σ, and ρ∗ (R) is the set of rules resulting from applying ρ to all rules in R. The following example illustrates the usefulness of this operation to adequate parameter names of a module. 204 J. M. Molina-Bravo and E. Pimentel Example 13 In the module OrdNatList\{isnat/1,leq/2} of Example 11 we can rename the function symbol isnat/1 with the new name isbasetype/1 to obtain a more appropriate parameterized module OrdList = {isnat/1 -> isbasetype/1}(OrdNatList\{isnat/1,leq/2}), where we have denoted the corresponding renaming function ρ as the set of pairs f/n → ρ(f/n) such that f/n 6= ρ(f/n). This module has the following appearance OrdList = <{isbasetype/1,leq/2}, {insert/2}, {insert(X,[]) -> [X] <= isbasetype(X) >< true. insert(X,[Y|Ys]) -> [X|[Y|Ys]] <= leq(X,Y) >< true. insert(X,[Y|Ys]) -> [Y|insert(X,Ys)] <= leq(X,Y) >< false.} > Now, the parameters become isbasetype/2 and leq/2. We will use this operation to change function names in exportation, importation and, specially, in instantiation for matching function names in the parameter signature of a module with function names in the exported signature of another module. See section 4.2 for some illustrative examples. Proposition 8 Renaming of modules has the following properties, where ρ, ρ1 and ρ2 are function symbol renamings, 1. 2. 3. 4. 5. 6. ι(P) = P, for every module P, where ι is the identity renaming. ρ(O) = O, for every ρ. ρ2 (ρ1 (P)) = (ρ2 ◦ ρ1 )(P), for all modules P and all ρ1 , ρ2 . ρ(P1 ∪ P2 ) = ρ(P1 ) ∪ ρ(P2 ), for all modules P1 , P2 and all ρ. σ ρ∗ (σ) , for all modules P, signatures σ and injective ρ. ρ(P ) = ρ(P) ρ(P \ σ) = ρ(P) \ ρ∗ (σ), for all modules P, signatures σ and injective ρ. 4.2 Other modular constructions in CRWL-programming Our notion of module is basically that of a program inside a context made up of other programs providing explicit rules for function symbols and implicit declarations of constructor symbols, all together defining a global signature Σ⊥ . In this section, we will show how the operations that we have defined above can be used to model typical module interconnections used in conventional modular programming languages. We will introduce new operations with modules for these relationships, but all these will be defined as derived expressions from the basic set. These expressions will reflect the relationship between the module denoted by the expression and its component modules, and the resulting modules will be interpreted as flat modules in all cases. The closure of a module M w.r.t. a signature σ gives a form of encapsulation, hiding those function symbols in M that are not in σ, and making the function symbols in M and σ visible but only in an extensional way, i.e. by the results – Composing programs in CRWL 205 as partial constructor Σ-terms – of the function applications to constructor Σ-terms (including variables). Thus, we can provide an export with encapsulation operation σ ‘’ over modules, in this simple way, σM =def M . The union of modules reflects the behavior of some logic programming systems that allow adding new programs – saved in separate files – to the main database. With this operation, but modifying one of its arguments, we can express different forms of importation and instantiation. We can define an import operation ≪ between modules as the union of a module M – representing the body of the importing module – with the closure of the imported module N as M ≪ N =def M ∪ N. Module M ≪ N imports N, which means that only the consequences of the functions defined in N are imported, and not their rules. When exp(M) ∩ exp(N) = σo we have a typical importation because functions defined in N are only reduced in N. We can also express selective importation of a signature σ from N by combining importation with exportation to restrict the visible signature of the imported module, as M ≪ (σN), with σ ⊆ exp(N). This expression is equivalent σ to M ∪ N by Proposition 6(4). Multiple importation or (selective) importation from several modules can be written as (. . . (M ≪ (σ1 N1 )) . . .) ≪ (σk Nk ), where the importation order is not relevant by Propositions 5(3,4) and 6(4,5). It can be easily proved that this expression is equivalent to the single importation M ≪ ((σ1 N1 ) ∪ . . . ∪ (σk Nk )). Importation with renaming can be expressed by an expression of the form M ≪ ρ(σN), with σ ⊆ exp(N) and an injective function symbol renaming ρ (see Proposition 8(5)). By the properties of renaming this σ expression is equivalent to M ≪ (ρ∗ (σ)ρ(N)) and can be reduced to M ∪ ρ(N ). Example 14 Let us consider the module OrdList in Example 13 and the new module OrdNat = < {}, {isnat/1, leq/2, geq/2}, { isnat(zero) -> true. isnat(succ(X)) -> isnat(X). leq(zero,zero) -> true. leq(zero,succ(X)) -> isnat(X). leq(succ(X),zero) -> false <= isnat(X) >< true. leq(succ(X),succ(Y)) -> leq(X,Y). geq(X,Y) -> leq(Y,X). } > where we define the predicate isnat/1 and the two order relationships leq/2 (less than or equal to) and geq/2 (greater than or equal to). The importation OrdList ≪ {isnat/1 -> isbasetype/1}(OrdNat) is a module with an infinite number of rules for isbasetype/1, leq/2 and geq/2 (all possible reductions to true or false), that behaves as calls to isbasetype/1 and leq/2 are reduced in OrdNat as calls to isnat/1 and leq/2 itself respectively. Thus a typical program M with a hierarchical structure in the sense of standard modular programming, i.e., importing from several modules N1 , . . . , Nk , possibly with renaming, can be built up from a plain program P – its body – and the 206 J. M. Molina-Bravo and E. Pimentel imported modules as M = P ≪ (ρ1 (σ1 N1 )∪. . .∪ρk (σk Nk )), with σ1 ⊆ exp(N1 ), . . . , σk ⊆ exp(Nk ) and par(P) ⊆ (ρ∗1 (σ1 )∪. . .∪ρ∗k (σk )). This expression can be reduced σ1 σk to P ∪ ρ1 (N1 ) ∪ . . . ∪ ρk (Nk ). Because our basic modules can be parameterized, we can instantiate function symbols of the parameterized signature of a module M with function symbols, of the same arity but different name, exported by other module N, simply by renaming suitably the parameters of M to fit (a part of) the exported signature of N. Thus we obtain an instantiation operation that we denote M[N, ρ] and define as M[N, ρ] =def ρ(M) ≪ N, where ρ is the function symbol renaming that characterizes the instantiation. This operation makes sense when ρ∗ (par(M)) ∩ exp(N) 6= σo . When par(ρ(M)) ⊆ exp(N) the instantiation is total and is partial in another case. Note that instantiation can be seen as a special form of importation. The difference between a (renamed) importation M ≪ ρ(N) and an instantiation ρ(M) ≪ N is that in the former, symbols in the parameter signature of M refer to actual names in the exported signature of the imported module N (renamed by ρ), whereas in the latter, symbols in the parameter signature of M behave as true parameters being replaced by ρ with actual values of the exported signature of N. Example 15 Let us consider again the module OrdList in Example 13 and the module OrdNat defined in Example 14. The instantiation OrdList[OrdNat,{isbasetype/1 -> isnat/1, leq/2 ->geq/2}] is equivalent to a module, also with an infinite number of rules, but defining the predicates isnat/1 and geq/2 instead of isbasetype/1 and leq/2 , respectively. Deletion of a signature σ in a module removes all rules defining function symbols in that signature but maintains the occurrences of these symbols in the rhs of the other rules. This operation can be used to abstract a signature σ from a module M in this way, M[σ] =def M \ σ. This abstraction operation makes sense when σ ⊆ exp(M) and each function symbol in σ appears in some rule of rl (M \ σ). This operation is very useful for making generic modules from concrete ones but unfortunately it is not implemented in conventional modular programming systems. As an example of the use of this operation we refer to Example 11. Also, with the deletion operation, we can model a sort of inheritance relationship between modules. Inheritance with overriding may be captured by means of union and deletion of a signature in this way, M isa N =def M ∪ (N \ exp(M)). Module M isa N inherits all functions in N – with their rules – not defined in M and uses the rules of M for all functions defined in M, overriding the definition rules in N, for common functions. In this case, overriding is carried out by deleting the common signature of the inherited module before adding it to the derived module. Example 16 Let us consider a module defining some operations on polygonal lines and parameterized w.r.t. an addition operation _+_/2, a predicate ispoint/1 to test if something Composing programs in CRWL 207 is a point, and operations distance/2 and translatepoint/2 for computing the distance between points and the point resulting of applying a translation, given by a vector (its second argument), to another point (its first argument). Polygonal = <{_+_/2, ispoint/1, distance/2, translatepoint/2 }, {perimeter/1,translate/2 }, {perimeter([P1]) -> zero <= ispoint(P1) >< true. perimeter([P1|[P2|Ps]]) -> distance(P1,P2)+perimeter([P2|Ps]). translate([P1],V) -> [translatepoint(P1,V)]. translate([P1|[P2|Ps]],V) -> [translatepoint(P1,V)|translate([P2|Ps],V)].} > (where we suppose that distance/2 and translatepoint/2 check that their arguments are points). Let us also consider another module defining some operations on squares and also parameterized w.r.t. a multiplication operation _*_/2, and the above operations ispoint/1 and distance/2. Square = < {_*_/2, ispoint/1, distance/2}, {issquare/1, side/1, perimeter/1, surface/1}, {issquare([P1,P2,P3,P4]) -> true <= distance(P1,P2) >< distance(P2,P3), distance(P2,P3) >< distance(P3,P4), distance(P1,P2) >< distance(P3,P4). side([P1,P2,P3,P4]) -> distance(P1,P2) <= issquare([P1,P2,P3,P4]) >< true. perimeter(C) -> 4*side(C) <= issquare(C) >< true. surface(C) -> side(C)*side(C) <= issquare(C) >< true.} >. With these modules we could define a new module SquarePolygone making module Square inherit from Polygonal, SquarePolygone = Square isa Polygonal. The resulting module would be SquarePolygone = < {_+_/2, _*_/2, ispoint/1, distance/2, translatepoint/2}, {issquare/1, side/1, perimeter/1, surface/1, translate/2}, {issquare([P1,P2,P3,P4]) -> true <= distance(P1,P2) >< distance(P2,P3), distance(P2,P3) >< distance(P3,P4), distance(P1,P2) >< distance(P3,P4). side([P1,P2,P3,P4]) -> distance(P1,P2) <= issquare([P1,P2,P3,P4]) >< true. perimeter(C) -> 4*side(C) <= issquare(C) >< true. surface(C) -> side(C)*side(C) <= issquare(C) >< true. translate([P1],V) -> [translatepoint(P1,V)]. translate([P1|[P2|Ps]],V) -> [translatepoint(P1,V)|translate([P2|Ps],V)].} >. Note that perimeter/1, defined in the module Polygonal, has been redefined with the version of the module Square. The function translate/2 has been inherited from Polygonal. 5 A compositional semantics A module is basically a program because its interface can be extracted from its set of rules when we know the data constructor symbols, and operations defined on modules are operations on their sets of rules, i.e. operations on programs. The difference between a program and a program module is that a module can be thought of as a program piece that can be assembled with other pieces to build larger programs (this is one of the main reasons of making explicit their interfaces). 208 J. M. Molina-Bravo and E. Pimentel With this idea in mind, the model-theoretic semantics defined for CRWL-programs is not suitable for program modules because it is not compositional w.r.t. the operations defined over modules as we can see in the following example. Example 17 Let Σ be a signature ({a/0, b/0, c/0}, {p/1, r/1}), and modules P1 and P2 with the following sets of rules: rl(P1 ) = {p(a) → c} and rl(P2 ) = {p(a) → c, r(b) → c ⇐ p(b) ⊲⊳ c}. These modules have the same model-theoretic semantics, MP1 = MP2 , which is the CRWL-algebra A with functions pA and rA such that pA (a) = {c, ⊥}, pA (b) = pA (c) = pA (⊥) = {⊥}, pA (X) = {⊥}, ∀X ∈ V rA (a) = {⊥}, rA (b) = rA (c) = rA (⊥) = {⊥}, rA (X) = {⊥}, ∀X ∈ V. However, their unions with Q, such that rl(Q) = {p(b) → c}, have different modeltheoretic semantics. The intended model of P1 ∪ Q has a function rMP1 ∪Q such that rMP1 ∪Q (b) = {⊥}, whereas rMP2 ∪Q (b) = {c, ⊥}. So, MP1 ∪Q 6= MP2 ∪Q . The compositionality of the semantics of a programming language is particularly relevant when modularity is involved. In fact, one of the most critical aspects in modular systems is the possibility of making a separate compilation of modules, and this can only be made in the presence of some kind of compositionality. To study the compositionality and full abstraction of a semantics, we have to clearly set out these notions. We will adopt the approach proposed in Brogi and Turini (1995), where compositionality and full abstraction are defined in terms of the equivalence relation between programs induced by the semantics. Definition 18 (Compositional relation) Given an equivalence relation ≡ defined between programs, an observation function Ob defined for programs, and a set Oper of operations with programs, we say that 1. ≡ preserves Ob iff for all programs P and Q, P ≡ Q ⇒ Ob(P) = Ob(Q); 2. ≡ is a congruence w.r.t. Oper iff for all programs Pi and Qi and all O ∈ Oper, Pi ≡ Qi , for i = 1, . . . , n, implies O(P1 , . . . , Pn ) ≡ O(Q1 , . . . , Qn ); 3. ≡ is compositional w.r.t. (Ob, Oper) iff it is a congruence w.r.t. Oper and preserves Ob. To set the notion of full abstraction for an equivalence relation, we need some way of distinguishing programs and for that reason we introduce the notion of context. Given a set of operations on programs Oper, and a metavariable X, we define contexts C [[ X ]] inductively as follows: X and each program is a context, also for each operation O ∈ Oper with n program arguments and C1 , . . . , Cn contexts, O(C1 , . . . , Cn ) is a context. Two programs P and Q are distinguishable under (Ob, Oper) if there exists a context C [[ X ]] such that C [[ P ]] and C [[ Q ]] have different external behavior, i.e. Ob(C [[ P ]] ) 6= Ob(C [[ Q ]] ). When P and Q are indistinguishable under (Ob, Oper) we will write P ∼ =Ob,Oper Q, i.e. for all contexts C, Ob(C [[ P ]] ) = Ob(C [[ Q ]] ). Definition 19 (Fully abstract relation) An equivalence relation ≡ is fully abstract w.r.t. (Ob, Oper) iff for all programs P and Q, P ∼ =Ob,Oper Q ⇒ P ≡ Q. Composing programs in CRWL 209 A semantics S for a programming language provides a meaning for programs and also induces an equivalence relation ≡S between programs: two programs are equivalent iff they have the same meaning in this semantics. This equivalence relation is used for defining compositionality and full abstraction for semantics. Definition 20 (Compositional and fully abstract semantics) A semantics S is compositional or fully abstract w.r.t. (Ob, Oper) iff its corresponding relation ≡S is compositional or fully abstract, respectively, w.r.t. (Ob, Oper). Obviously, for each pair (Ob, Oper) there exits a compositional and fully abstract relation between programs, the relation P ≡(Ob,Oper) Q iff Ob(C [[ P ]] ) = Ob(C [[ Q ]] ), for every context C [[ X ]] . For each compositional equivalence relation ≡, it is easy to see that P ≡ Q ⇒ P ≡(Ob,Oper) Q, and for each fully abstract equivalence relation ≡, P ≡(Ob,Oper) Q ⇒ P ≡ Q. Thus, ≡(Ob,Oper) will be the only equivalence relation which is both compositional and fully abstract w.r.t. (Ob, Oper). And the more adequate semantics for programs (w.r.t. (Ob, Oper)) will be a semantics that induces this relation. 5.1 The T-semantics To find a compositional semantics we may think about programs as open in the sense that we can build up programs from other programs adding rules for new functions and also for already defined functions (of the signature Σ we were in) and imagine them as algebra transformers as is done in Mancarella and Pedreschi (1988) and Brogi (1993). The operator TP considered as a function TAlgΣ → TAlgΣ is a good candidate for the intended meaning of a program P. First, we have to note that the set [TAlgΣ → TAlgΣ ] of all continuous functions from TAlgΣ to TAlgΣ , ordered by the relation T1 ⊑ T2 iff T1 (A) ⊑ T2 (A), for all A ∈ TAlgΣ , with the least upper bound and the greatest lower bound of a finite set {Ti }i∈I of functions pointwise defined as (⊔i∈I Ti )(A) = ⊔i∈I (Ti (A)) and (⊓i∈I Ti )(A) = ⊓i∈I (Ti (A)) respectively, and with bottom T⊥ and top TΣ such that T⊥ (A) = ⊥Σ and TΣ (A) = ⊤Σ , for all A ∈ TAlgΣ , is a complete lattice as a consequence of (TAlgΣ , ⊑) being a complete lattice. Now, we can associate a program with the corresponding immediate consequence operator, instead of its least fixpoint. Definition 21 (T-semantics) We define the T-semantics {[ P ]}T by denoting the meaning of a program P by its algebra transformer TP , where TP is intended as Trl(P) . This semantics entails the following equivalence relation on programs: P ≡T Q ⇔def TP = TQ . Thus, two programs are ≡T -equivalent if both define the same immediate consequences operator. In this context, and coinciding with logic programming, a natural choice of the observable behavior of a program R is its modeltheoretic semantics. So we will adopt as observation function Ob(R) =def MR . Notice that MR captures the graphs of all functions defined in R, whereas functions not included in the program are considered totally undefined (their images only can be reduced to ⊥). The semantics {[ · ]}T is compositional w.r.t. this observation σ function and the set of operations Oper = {∪, (·) , (·)\σ, ρ(·)}. We can prove this fact by proving that {[ · ]}T is homomorphic in the following sense. 210 J. M. Molina-Bravo and E. Pimentel Theorem 22 Given a global signature Σ and a countable set of variable symbols V, for all programs P, P1 and P2 defined over Σ, every subsignature of function symbols σ ⊆ FSΣ , and every function symbol renaming ρ, we have the following results (a) (b) (c) (d) {[ P1 ∪ P2 ]}T σ {[ P ]}T {[ P \ σ ]}T {[ ρ(P) ]}T = {[ P1 ]}T ⊔{[ P2 ]}T ; = λA · ( {[ P ]}ω T (⊥Σ ))|σ ; = {[ P ]}T ⊓ Texp(P)\σ ; = Tρ−1 ◦ {[ P ]}T ◦Tρ ; where, for every algebra A ∈ TAlgΣ and every subsignature σ ⊆ FSΣ , A|σ is the term algebra characterized by f A|σ (t) = f A (t), for f/n ∈ σ, and f A|σ (t) = {⊥}, otherwise. For each subsignature σ ⊆ FSΣ , Tσ is the constant algebra transformer that, for all A ∈ TAlgΣ produces the same term algebra ⊤σ characterized by f ⊤σ (t) = CTerm⊥ , for f/n ∈ σ, and f ⊤σ (t) = {⊥}, otherwise. And, for each rename ρ, Tρ and Tρ−1 are the algebra transformers defined by Tρ (A) = Aρ and Tρ−1 (A) = Aρ−1 where Aρ and Aρ−1 are the term algebras characterized by  ⊔{g A | f = ρ(g)}, when this set is not empty, Aρ−1 Aρ A and f = f = ρ(f) otherwise, f ⊥Σ for every function symbol f in FSΣ . Thus, the meaning of the union of two programs (a) can be extracted from the meaning of each one, the meaning of the closure of a program (b) is obtained from the fixpoint of the program semantics, and deleting a signature from a program (c) is semantically equivalent to the intersection of the program semantics with an algebra transformer which depends on the exported signature of the program. Nevertheless, the intersection we are mentioning here is not an operation over programs (as in Brogi (1993)) but an operation on algebra transformers. The meaning of a renamed program (d) can be obtained as the composition of the meaning of the program with two algebra transformers associated with the renaming and its reverse. Corollary 1 (Compositionality of {[ · ]}T ) σ The semantics {[ · ]}T is compositional with respect to (Ob, {∪, (·) , (·)\σ, ρ(·)}). As the above corollary states, {[ · ]}T is compositional w.r.t. union, closure, deletion and renaming, when the canonic model of a program is taken as its observable behavior. However, the following example shows that it is not fully abstract. Example 23 Let Σ be a signature ({c/0, d/0}, {f/0}) and let P and Q be the modules such that rl(P) = {f → c, f → d} and rl(Q) = {f → c, f → d ⇐ f ⊲⊳ c}. They are σ indistinguishable under {∪, (·) , (·)\σ, ρ(·)}, but they are not ≡T -equivalent. In fact, TP (⊥Σ ) 6= TQ (⊥Σ ) because f TP (⊥Σ ) = {c, d, ⊥} whereas f TQ (⊥Σ ) = {c, ⊥}. The T-semantics distinguishes more than the model-theoretic semantics, since the immediate consequence operator captures what is happening in each reduction step, but the non-full abstraction result means that this semantics distinguishes more than necessary. It is too fine. In the next section we will try a coarser semantics – also 211 Composing programs in CRWL studied in logic programming (Brogi and Turini, 1995) – defined from the sets of pre-fixpoints of T. 6 A fully abstract semantics In this section, a fully abstract semantics is presented, which is also compositional except for the deletion operation. For a better motivation, we will not introduce this semantics directly. Instead, we will define a first approximation, the so-called term model semantics (Definition 24), which only is compositional (w.r.t. the union, closure and renaming operations), and then we will obtain the full abstraction property by restricting the term models (Definition 29). 6.1 The term model semantics Formally, we will introduce the first semantics by directly considering the corresponding equivalence relation. Definition 24 (Model equivalence) Two programs P and Q are model-equivalent, P ≡M Q, iff their algebra transformers have the same pre-fixpoints. By Lemma 3 this means that two programs are equivalent iff they have the same term models. This equivalence relation corresponds to the following semantics: {[ P ]}M =def {M | M is a term model of P} which will be called loose model-theoretic semantics, or simply term model semantics. To derive the corresponding result about compositionality, we need an auxiliary property about Tρ and Tρ−1 . Lemma 5 Given two term algebras A, B ∈ TAlgΣ , for every function symbol renaming ρ, Aρ−1 ⊑ B ⇔ A ⊑ Bρ or, equivalently, Tρ−1 (A) ⊑ B ⇔ A ⊑ Tρ (B). This lemma claims that Tρ−1 is, essentially, the reverse operator for Tρ . Theorem 25 (Compositionality of {[ · ]}M ) For all programs P, Q, Pi , Qi , 1. 2. 3. 4. P ≡M Q implies Ob(P) = Ob(Q). Pi ≡M Qi for i = 1, 2, implies P1 ∪ P2 ≡M Q1 ∪ Q2 . σ σ P ≡M Q implies P ≡M Q , for every signature σ. P ≡M Q implies ρ(P) ≡M ρ(Q), for every function symbol renaming ρ. σ Therefore, the semantics {[ · ]}M is compositional w.r.t. (Ob, {∪, (·) , ρ(·)}). Unfortunately, this semantics is not compositional w.r.t. deletion. 212 J. M. Molina-Bravo and E. Pimentel Example 26 Let Σ be the signature ({a/0, b/0}, {f/0, g/0}) and let P and Q be two modules with rules rl(P) = {f → a, g → b} and rl(Q) = {f → a, g → b ⇐ f ⊲⊳ a}. Both modules have the same term models, those term algebras A with a ∈ f A and b ∈ g A . But by deleting f/0 in each module we have P \ {f/0} and Q \ {f/0} with rl(P \ {f/0}) = {g → b} and rl(Q \ {f/0}) = {g → b ⇐ f ⊲⊳ a}, and now ⊥Σ is a model of Q \ {f/0} whereas it is not a model of P \ {f/0}. For a different reason, the semantics {[ · ]}M is not fully abstract. Example 27 Let Σ be the signature ({a/0}, {f/0, g/1}) and let P and Q be two modules with rules rl(P) = {f → a ⇐ g(a) ⊲⊳ a} and rl(Q) = {f → a ⇐ g(X) ⊲⊳ a}, where the rule in P is an instance of the rule in Q. Obviously, both modules are indistinguishable but they do not have the same term models. In fact, if we consider the algebra A such that: f A = {⊥}, g A (X) = {a, ⊥} and g A (a) = {⊥}, A is a model of P but it is not a model of Q. 6.2 The consistent term model semantics To prove the full abstraction property we need to consider a different equivalence relation (i.e. semantics). If we observe the above counter-example, we can see that, for the term algebra A used to distinguish {[ P ]}M from {[ Q ]}M , g A (X) = {a, ⊥} and g A (a) = {⊥}; that is, A is such that the instantiation of the variable X derives in a loss of information for the interpretation of g because g A (Xθ) is smaller than (g A (X))θ, for θ = {X/a}. In general, the notion of term algebra (see section 2) does not impose any relation between g A (t̄θ) and (g A (t̄))θ. This is not reasonable if we take into account the role of term algebras when they are used to model programs. On the contrary, the interpretation of a function symbol (in a term algebra) applied to arguments with variables must be related to the interpretation of the same function symbol when these variables are instantiated. With this idea in mind, we introduce the notion of consistency in a term algebra. Definition 28 (Consistency of term algebras) A term algebra A ∈ TAlgΣ is consistent iff for every f ∈ FSΣn and ti ∈ CTerm⊥ (i = 1, . . . , n), f A (tθ) ⊇ (f A (t))θ for all θ ∈ CSubst, where (f A (t))θ stands for the set {uθ | u ∈ f A (t)}. We denote by CTAlgΣ the family of all consistent term algebras. Note that consistency is only required for total substitutions (i.e. substitutions which do not include partial constructor terms). This is due to the special treatment of ⊥, which is considered as lack of information. The notion of consistency here introduced is close to that of closure under substitutions defined for interpretations in Apt (1996), and is also related with the notion of C-interpretation considered in Falaschi et al. (1993), but our requirements are weaker than those. To justify the reasonable nature of consistent term algebras we will prove several desirable properties. For instance, the immediate consequences operator maps consistent algebras into consistent algebras, and the canonical model of a program is consistent. 213 Composing programs in CRWL Lemma 6 A For every A ∈ CTAlgΣ , r ∈ Term⊥ , and θ ∈ CSubst, [[ r ]] A id θ ⊆ [[ rθ ]] id . Proposition 9 Given a program P, if A ∈ CTAlgΣ , then TP (A) ∈ CTAlgΣ . Proposition 10 Given a program P, the canonical term model MP is consistent. Now, we may define an equivalence relation based only on consistent term models. Definition 29 (Consistent model equivalence) Two programs P and Q are consistent model-equivalent, P ≡CM Q, iff their have the same consistent models. This equivalence is clearly weaker than the model equivalence and corresponds to the following semantics: {[ P ]}CM =def {M | M is a consistent term model of P} which will be called loose consistent model-theoretic semantics, or simply consistent term model semantics. Obviously, {[ P ]}CM = {[ P ]}M ∩ CTAlgΣ , and the compositionality property of this semantics may be obtained in a similar way as the compositionality of the term model semantics. Theorem 26 (Compositionality of {[ · ]}CM ) For all programs P, Q, Pi , Qi , 1. 2. 3. 4. P ≡CM Q implies Ob(P) = Ob(Q). Pi ≡CM Qi for i = 1, 2, implies P1 ∪ P2 ≡CM Q1 ∪ Q2 . σ σ P ≡CM Q implies P ≡CM Q , for every signature σ. P ≡CM Q implies ρ(P) ≡CM ρ(Q), for every function symbol renaming ρ. σ Therefore, the semantics {[ · ]}CM is compositional w.r.t. (Ob, {∪, (·) , ρ(·)}). Example 26 also illustrates the non-compositionality of {[ · ]}CM w.r.t. the deletion operation because the programs P and Q only define functions without arguments. However, this semantics is fully abstract; to prove this fact, we need an auxiliary result, showing how a (minimal ) program P can be constructed from a consistent term algebra A and an element t ∈ [[ r ]] A id such that A is a model of P and P . Proposition 11 formalizes this idea. In order to simplify the proof of t ∈ [[ r ]] M id this result, we will prove some properties about the notion of canonical rewrite rule already introduced in Definition 6. Lemma 7 For each canonical rewrite rule crr(e, r), T{crr(e,r)} is constant and if e = f(t) then, for every term algebra A, ( S A η∈CSubst { [[ rη ]] id | tη ⊑ s} ∪ {⊥} if h = f, T{crr(e,r)} (A) (s) = h {⊥} otherwise 214 J. M. Molina-Bravo and E. Pimentel Proposition 11 Let A ∈ CTAlgΣ be a consistent term algebra, and r ∈ Term⊥ . Then, for every MRt and TRt (A) ⊑ A. Moreover, t ∈ [[ r ]] A id , a program Rt exists such that t ∈ [[ r ]] id TRt is constant. Now, we can obtain the full abstraction property for {[ · ]}CM . Theorem 31 (Full abstraction of {[ · ]}CM ) σ The semantics {[ · ]}CM is fully abstract w.r.t. (Ob, {∪, (·) , (·)\σ, ρ(·)}) 7 A compositional and fully abstract semantics The fact that the consistent term model semantics is fully abstract but not compositional w.r.t. the deletion of a subsignature means that this semantics is more abstract than necessary. We need a finer semantics but not as fine as the T-semantics. One way of obtaining such a semantics is by increasing the number of pre-fixpoints (related to the T-operator) to be considered when we compare two programs, and to obtain compositionality w.r.t. the deletion operation, we may consider the consistent term models of all programs obtained by deleting a subsignature. With this idea we define the following equivalence between programs Definition 32 (Deletion equivalence) For programs P and Q, we define the deletion equivalence P ≡D Q as P\σ ≡CM Q\σ for all subsignatures σ ⊆ FSΣ . This equivalence is finer than the consistent model equivalence and coarser than the equivalence induced by the T-semantics. In fact, P ≡D Q implies P ≡CM Q because this relationship coincides with P \ σ0 ≡CM Q \ σ0 , where σ0 is the empty signature. And if P ≡T Q, or equivalently TP = TQ , it can be proved that TP\σ = TQ\σ , for all σ ⊆ FSΣ , and then P \ σ ≡CM Q \ σ, for all σ ⊆ FSΣ , which is P ≡D Q. The deletion equivalence is compositional w.r.t. all operations. Theorem 33 (Compositionality of ≡D ) For all programs P, Q, Pi , Qi , 1. 2. 3. 4. 5. P ≡D Q implies Ob(P) = Ob(Q). Pi ≡D Qi for i = 1, 2, implies P1 ∪ P2 ≡D Q1 ∪ Q2 . σ σ P ≡D Q implies P ≡D Q , for every signature σ ⊆ FSΣ . P ≡D Q implies P \ σ ≡D Q \ σ, for every signature σ ⊆ FSΣ . P ≡D Q implies ρ(P) ≡D ρ(Q), for every function symbol renaming ρ. σ Thus, the equivalence ≡D is compositional w.r.t. (Ob, {∪, (·) , (·) \ σ, ρ(·)}). Theorem 34 (Full abstraction of ≡D ) σ The equivalence ≡D is fully abstract w.r.t. (Ob, {∪, (·) , (·)\σ, ρ(·)}) Definition 35 (Deletion semantics) We define the deletion semantics {[ P ]}D , of a program P, as {Mf/n (P) | f/n ∈ FSΣ }, where Mf/n (P) is the set of all consistent term models of the rules of P that define f/n. The deletion semantics induces the deletion equivalence. Composing programs in CRWL 215 Proposition 12 P ≡D Q ⇔def {[ P ]}D = {[ Q ]}D σ Thus, the deletion semantics is compositional and fully abstract w.r.t. (Ob,{∪, (·) , (·) \ σ, ρ(·)}). 8 Introducing hidden symbols In this section we explore an alternative to modules with an infinite number of rules, generated by the closure operation, that also supports local constructor symbols. For this aim we will consider a global or visible signature Σ and a set V of variable symbols together with a new set Ω of labels that we identify with the set of module names and module expressions. With this set we obtain a labeled signature Ω × Σ = (Ω × DSΣ , Ω × FSΣ ) which we will consider as protected or non accessible for users and writers of modules, i.e. hidden. This signature will be only managed by the module system for internal representation of module expressions. Pairs (M, f) of Ω × Σ, called labeled symbols, will be denoted by M.f. As we have seen in section 4.1 the purpose of the closure of a module is to hide the definitions of function symbols, making only their results visible. To this aim, the rules of a module are replaced with all (possibly infinite) approximations that can be derived from them. However, we can obtain an internal representation of the closure operation, with a finite number of rules, with the aid of labeled symbols, following an idea that appears in Brogi (1993) applied to the hiding of predicate definitions in logic programs. We go further into this idea applying it to deal with local constructor symbols. 8.1 A finite representation of closure Let P =< σp , σe , R > a module of PMod(Σ⊥ ) with a finite set of rules. We can protect its rules translating them to a protected signature by labeling all function symbols with the module’s name and introducing a bridge rule f(X) → P.f(X) for each function symbol f/n ∈ σe . In this way we obtain a module P∗ in the signature Σ⊥ = (DSΣ⊥ , FSΣ⊥ ∪ (Ω × FSΣ⊥ )) with an isolated (hidden) part RH , made up of all translated rules, and a bridge part RB for accessing the isolated part, made up of all bridge rules. Obviously with this module we can derive the same approximations, for visible function symbols, as with P in every context. We will call these modules structured modules to distinguish them from plain modules used up to now. In general, a structured module will be a module < σp , σe , RV ∪ RB ∪ RH > with a visible parameter signature σp , a visible exported signature σe , and a set of rules with three – possibly empty – parts, a visible part RV made up of rules only with function symbols in FSΣ , a hidden part RH made up of rules only with function symbols in Ω × FSΣ , and a bridge part RB made up of bridge rules f(X) → P.g(X), for any label P ∈ Ω, such that each symbol P.g has a definition rule in RH . Also, σe is made up of all function symbols with a definition rule in RV or RB , and σp is made up of all parameter function symbols which appear in RV . We define 216 J. M. Molina-Bravo and E. Pimentel union, deletion of functional signature and renaming in the same way as we did in section 4.1, but we will use deletion and renaming involving only visible signature, and, instead of closure, we define a structured closure for a structured module P =< σp , σe , RV ∪ RB ∪ RH > as the module P∗ =< ∅, σe , R∗B ∪ R∗H > obtained by applying the renaming τ(P), that transforms each visible function symbol f of RV and RB into P.f and maintains all labeled symbols, and adding new bridge rules corresponding to the function symbols of σe . Now, we can define a representation morphism from modular expressions made up from finite plain modules to structured modules in the following way: • • • • ι(P) = P, for each finite plain module P; ι(P ∪ Q) = ι(P) ∪ ι(Q), for module expressions P and Q; ι(P \ σ) = ι(P) \ σ, for each module expression P and visible signature σ; ι(ρ(P)) = ρ(ι(P)), for each module expression P and visible signature renaming ρ; • ι(P) = (ι(P))∗ , for each module expression P. Example 36 Let OrdList and OrdNat be the modules defined in Examples 13 and 14, respectively, and let P be the name of the module ι(OrdNat). The representation of OrdList ∪ {isnat/1->isbasetype/1}(OrdNat) will be the structured module ι(OrdList) ∪ {isnat/1->isbasetype/1}(P∗ ), with the following aspect <{}, {isbasetype/1,leq/2,geq/2,insert/2}, { % visible rules insert(X,[]) -> [X] <= isbasetype(X) >< true. insert(X,[Y|Ys]) -> [X|[Y|Ys]] <= leq(X,Y) >< true. insert(X,[Y|Ys]) -> [Y|insert(X,Ys)] <= leq(X,Y) >< false. % bridge rules isbasetype(X) -> P.isnat(X). leq(X,Y) -> P.leq(X,Y). geq(X,Y) -> P.geq(X,Y). % hidden rules P.isnat(zero) -> true. P.isnat(succ(X)) -> P.isnat(X). P.leq(zero,zero) -> true. P.leq(zero,succ(X)) -> P.isnat(X). P.leq(succ(X),zero) -> false <= P.isnat(X) >< true. P.leq(succ(X),succ(Y)) -> P.leq(X,Y). P.geq(X,Y) -> P.leq(Y,X). } > The behaviour of a structured module P =< σp , σe , RV ∪RB ∪RH > w.r.t. the visible signature can be expressed with the aid of the algebra transformer UP : CTAlgΣ → CTAlgΣ defined, for each A, as UP (A) = TRV ∪RB (Tω RH (⊥Σ ) ⊔ A)|Σ , where A is the extension of A to an algebra of CTAlgΣ obtained by adding functions P.f A defined as P.f A (t) = h⊥i, for each f/n ∈ FSΣ and P ∈ Ω, and B|Σ means the reduct of the algebra B ∈ CTAlgΣ obtained by forgetting all functions denoting labeled function symbols. In this expression, Tω RH (⊥Σ ) represents all the information which can be obtained from the hidden rules; this information is added to the extended algebra because it has to be available for the immediate consequences operator Composing programs in CRWL 217 corresponding to the visible and bridge rules, to obtain the approximations for visible functions. The relationship, at the semantical level, between programs and structured modules is given in the following theorem. Theorem 37 For each modular expression E, made up from finite plain programs, and its implementation ι(E), we have TE = Uι(E) . From this theorem we obtain that for two equivalent module expressions P and Q (i.e. P and Q have the same components but, possibly, different expressions with the operations), Uι(P) = Uι(Q) although it is possible that ι(P) differs from ι(Q) due to the occurrence of closure operations. Also, the models of a program module P will be the pre-fixpoints of Uι(P) and we can define the visible semantics of structured modules based on this operator. In particular we obtain the deletion semantics by considering, for each structured module P =< σp , σe , RV ∪ RB ∪ RH >, the indexed family of sets of pre-fixpoints of UP\(σe \f) for each f/n ∈ σe . 8.2 Local constructor symbols To simplify the theoretical study of programs composition in CRWL-programming, and to capture the idea of module as open program, we have assumed that constructor symbols are common to all programs. However, as it was discussed in section 4, this assumption prevents to hide constructor symbols, what is not acceptable from a practical point of view. We can hide constructor symbols by labeling them as we have done with function symbols to protect them against user manipulations. Labeled constructor symbols can only be manipulated in the internal representation of the closure of the module corresponding to their label. Outside this module, function symbols defined on labeled constructor symbols can only be applied to variable symbols or to other function applications that can be reduced to this labeled constructor symbols. To realize this idea we only need to modify our closure implementation extending it to manage constructor symbols also. So, we define closure hiding a subsignature C of constructor symbols for a module P as a (non plain) module PC such that ι(PC ) = P∗C where P∗C is obtained as P∗ but now the renaming τ(P) also transforms each visible constructor symbol c of C into P.c. Example 38 Let us suppose a module LNat for lists of natural numbers exporting the function symbols isnat/1, _<_/2 and _++_/2, and consider the following module for binary search trees where tree constructors nil/0 and mktree/3 are used. BST = <{isnat/1, _<_/2, _++_/2}, {empty/0, insert/2, inorder/1}, {empty -> nil . insert(N,nil) -> mktree(N,nil,nil) <= isnat(N) >< true . insert(N,mktree(M,T1,T2)) -> mktree(M,T1,T2) <= N >< M, isnat(N) >< true . insert(N,mktree(M,T1,T2)) -> mktree(M,insert(N,T1),T2) <= N<M >< true . insert(N,mktree(M,T1,T2)) -> mktree(M,T1,insert(N,T2)) <= M<N >< true . inorder(nil) -> [] . inorder(mktree(M,T1,T2)) -> inorder(T1)++[M|inorder(T2)] <= isnat(M) >< true .}> 218 J. M. Molina-Bravo and E. Pimentel We may hide the tree constructors by considering (LNat ∪ BST){nil,mktree} . This module will have the following representation: <{}, {isnat/1, _<_/2, _++_/2, empty/0, insert/2, inorder/1}, { ... % bridge rules of LNat empty -> BST.empty . % bridge rules of BST insert(N,T1) -> BST.insert(N,T1) . inorder(T1) -> BST.inorder(T1) . ... % hidden part of LNat BST.empty -> BST.nil . % hidden part of BST BST.insert(N,BST.nil) -> BST.mktree(N,BST.nil,BST.nil) <= BST.isnat(N) >< true . BST.insert(N,BST.mktree(M,T1,T2)) -> BST.mktree(M,T1,T2) <= N >< M, BST.isnat(N) >< true . BST.insert(N,BST.mktree(M,T1,T2)) -> BST.mktree(M,BST.insert(N,T1),T2) <= N NBST.< M >< true . BST.insert(N,BST.mktree(M,T1,T2)) -> BST.mktree(M,T1,BST.insert(N,T2)) <= M MBST.< N >< true . BST.inorder(BST.nil) -> [] . BST.inorder(BST.mktree(M,T1,T2)) -> BST.inorder(T1) BST.++ [M|BST.inorder(T2)] <= BST.isnat(M) >< true .}> We can use this module, only using the exported signature and visible constructor symbols, as is done in the following module for sorting lists: LSort = <{empty/0, insert/2, inorder/1}, {listTotree/1, lsort/1}, {listTotree([]) -> empty . listTotree([N|L]) -> insert(N,listTotree(L)) . lsort(L) -> inorder(listTotree(L)) .} > The behavior of a structured module P =< σp , σe , RV ∪ RB ∪ RH > with hidden constructor symbols w.r.t. the visible signature can be expressed with the aid of the algebra transformer UP : CTAlgΣ → CTAlgΣ defined, for each A, as UP (A) = TRV ∪RB (Tω RH (⊥Σ ) ⊔ A)|Σ , where now A is the extension of A to an algebra of CTAlgΩ×Σ obtained by adding functions P.f A , defined as P.f A (t) = h⊥i, for each ∗ ∗ f/n ∈ FSΣ and P ∈ Ω, and defining f A (t) = f A (t ) where tuple t is obtained from t by changing each term beginning with a labeled constructor term for ⊥, for each f/n ∈ FSΣ , and B|Σ means the reduct of the algebra B ∈ CTAlgΩ×Σ obtained by restricting the carrier to CTerm⊥ and forgetting all functions denoting labeled function symbols. Obviously, the representation of the closure w.r.t. the functional signature is a particular case of closure hiding a set of constructor symbols when this set is empty. 9 Discussion Research in component-based software development is currently becoming a very active area for the logic programming community. In fact, we can find several proposals in the field of computational logic for dealing with the design and development of large software systems. Other related fields, like functional-logic programming are now proving that the integration of logic variables and functions may increase the expressive power of a programming language. A number of Composing programs in CRWL 219 attempts are being made in this direction (Hanus, 1994, 1998) to achieve a consensus on the characteristics a functional-logic language has to present. The current work tries to contribute to all these efforts by presenting a notion of module in the context of functional-logic programming, and by providing a number of operations (satisfying some expected algebraic properties) expressive enough to model typical modularization issues like export/import relationships, hiding information, inheritance, and a sort of abstraction. We have chosen the Constructor-based Conditional Rewriting Logic (González-Moreno et al., 1999) to develop our proposal and, in this context, we have explored a rather wide range of semantics for program modules and we have studied some of their relevant properties, in particular, those concerning compositionality and full abstraction σ w.r.t. the observation function Ob(P) = MP and the set {∪, (·) , (·) \ σ, ρ(·)} of module operations. Although these features are interesting enough from a theoretical point of view, they present a special significance when module reusing, module refining or module transforming are involved. The least model semantics, {[ · ]}LM , is a fully abstract σ semantics, which is only compositional w.r.t. {(·) , ρ(·)}, but only for injective function renamings ρ. On the contrary, the T-semantics, {[ · ]}T , is compositional (w.r.t. all operations), but is not fully abstract. The third proposal, the loose model-theoretic semantics, {[ · ]}M , is also compositional (except for the deletion operation), although the full abstraction property is not satisfied. A fully abstract semantics, {[ · ]}CM , may be obtained by considering a consistency property on term algebras, which is also compositional w.r.t. the union, closure and renaming operations. To recover the compositionality w.r.t. deletion we need a finer semantics able to capture the ‘independent’ meaning of each function in a module; this is the case of the deletion semantics, {[ · ]}D , which still is fully abstract and compositional w.r.t. all operations. We have also studied the (T ⊔ Id)-semantics, {[ · ]}T ⊔I , but we have not included this study in this paper because it exhibits the same properties as the T-semantics. Table 1 summarizes the properties satisfied by each one of the analyzed semantics. It is possible to establish a semantics hierarchy ranging from the model-theoretic semantics to the T-semantics on the basis of the order ≡T ⊑ ≡T ⊔Id ⊑ ≡D ⊑ ≡CM ⊑ ≡C for the equivalence relationships induced by these semantics, where they are ordered upon their strength. The T-equivalence relation, ≡T , is the strongest one, and it is contained obviously into the (T ⊔ Id)-equivalence relation, ≡T ⊔Id . Taking into account that this equivalence relation is compositional but not fully abstract, it will be contained in ≡D , which is also contained in the consistent term-model equivalence, ≡CM . Obviously, the least term-model equivalence, ≡LM , is the weakest one. To establish some conclusions about the compositionality and the full abstraction of all these semantics, we are going to discuss the information exhibited in Table 1. In this table, we can observe a sort of dependency between fulfilling compositionality/full abstraction and the strength of the equivalence relationship defined by the semantics, in such a way that the strongest ones are compositional whereas the weakest ones are fully abstract. The best semantics must be an intermediate semantics satisfying both properties; in our case, the semantics {[ · ]}D . A similar 220 J. M. Molina-Bravo and E. Pimentel Table 1. Compositionality (C) and full abstraction (FA) σ ∪, (·) , (·)\σ, ρ(·) σ ∪, (·) , ρ(·) σ (·) , ρ(·) (·) σ {[ · ]}T C C C C {[ · ]}T ⊔I C C C C C C C C C C C {[ · ]}D FA {[ · ]}CM FA FA {[ · ]}LM FA FA FA FA C study was already made by Brogi and Turini (1995) in the field of logic programming, but he did not deal with variables, and avoided the complexity inherent to the non-ground term algebras. Another difference (apart from the context) with respect to the current work is the set of operations we are considering, which does not coincide with the set of inter-module operations defined by Brogi. One of the most significative operations described by him is the intersection of programs. This operation makes the (T ⊔ Id)-semantics compositional and fully abstract in a logic programming context. However, the difficult justification of this operation in our framework (the functional-logic programming paradigm) has inclined us to think in an alternative: the deletion operation. We believe that this operation is more natural (as a composing mechanism) than program intersection. This has an inconvenience: the (T ⊔ Id)-semantics is not fully abstract (although it is compositional) w.r.t. our operations. In fact, the intersection of programs is a very powerful tool to distinguish programs (more than the deletion operation), and it can be used to delete a single rule, whereas our deletion operation only can be used to delete a whole set of rules defining a function. Nevertheless, we have found a fully abstract and compositional semantics, also for the deletion operation, which completes the results provided by this work. Acknowledgements We would like to thank Mario Rodrı́guez-Artalejo and Ana Gil Luezas for their helpful comments and suggestions on the initial versions of this work. We would also like to thank Narciso Martı́-Oliet for their insightful comments and suggestions, that greatly helped us improving the quality and presentation of the paper. This work has been partially supported by the Spanish project TIC98-0445-C03-03. References Abramsky, S. and Jung, A. (1994) Domain theory. Handbook of Logic in Computer Science, 3, 1–168. Oxford University Press. Apt, K. (1990) Logic programming. Handbook of Theoretical Computer Science, Vol. B: Formal Models and Semantics, pp. 493–574. Elsevier. Apt, K. (1996) From Logic Programming to Prolog. Prentice-Hall. Composing programs in CRWL 221 Bergstra, J. A., Heering, J. and Klint, P. (1990) Module algebra. J. ACM, 37(2), 335–372. Brogi, A. (1993) Program Construction in Computational Logic. PhD Thesis TD-2/93, University of Pisa-Genova-Udine. Brogi, A., Mancarella, P., Pedreschi, D. and Turini, F. (1994) Modular Logic programming. ACM Trans. Program. Lang. & Syst. 16(4), 1361–1398. Brogi, A. and Turini, F. (1995) Fully abstract compositional semantics for an algebra of logic programs. Theor. Comput. Sci. 149(2), 201–229. Bugliesi, M., Lamma, E. and Mello, P. (1994) Modularity in logic programming. J. Logic Program. 19(20), 443–502. Durán, F. (1999) A Reflective Module Algebra with Applications to the Maude Language. PhD Thesis, University of Málaga. Ehrig, H. and Mahr, B. (1990) Fundamentals of Algebraic Specification 2. Module Specifications and Constraints. Springer-Verlag. Falaschi, M., Levi, G., Martelli, M. and Palamidessi, C. (1993) A model-theoretic reconstruction of the operational semantics of logic programs. Infor. & Computation, 102(1), 86–113. Goguen, J. A. and Burstall, C. R. M. (1992) Institutions: abstract model theory for specification and programming. J. ACM, 39(1), 95–146. González-Moreno, J. C. (1994) Programación Lógica de Orden Superior con Combinadores. PhD Thesis, Universidad Complutense de Madrid. González-Moreno, J. C., Hortalá-González, M. T., López-Fraguas, F. J. and Rodrı́guezArtalejo, M. (1999) An approach for declarative programming based on a rewriting logic. J. Logic Programl. 40(1), 47–88. Hanus, M. (1994) The integration of functions into logic programming. A survey. J. Logic Program. 19(20), 583–628. Hanus, M. (ed.) (2000) Curry. An Integrated Functional Logic Language. Draft (available at: www.informatik.uni kiel.de/˜mh/curry/report.html). Hussmann, H. (1993) Non-determinism in Algebraic Specifications and Algebraic Programs. Birkäuser Verlag. Mancarella, P. and Pedreschi, D. (1988) An algebra of logic programs. In: Kowalski, R. A. and Bowen, A. (eds.) Proc. 5th International Conference on Logic Programming, pp. 1006–1023. MIT Press. Meseguer, J. (1992) Conditional rewriting logic as a unified model of concurrency. Theor. Comput. Sci. 96, 73–155. Miller, D. (1986) A theory of modules in logic programming. Proc. of Symposium of Logic Programming, pp. 106–114. Molina-Bravo, J. M. and Pimentel, E. (1997) Modularity in functional-logic programming. Proc. 14th International Conference on Logic Programming, pp. 183–197. MIT Press. Molina-Bravo, J. M. (2000) Modularidad en Programación Lógico-Funcional de Primer Orden. PhD Thesis, University of Málaga. Möller, B. (1985) On the algebraic specification of infinite objects – ordered and continuous models of algebraic types. Acta Informatica, 22, 537–578. Orejas, F., Pino, E. and Ehrig, H. (1997) Institutions for logic programming. Theor. Comput. Sci. 173, pp. 485–511. Orejas, F. (1999) Structuring and modularity. In: Astesiano, E., Kreowski, H.-J. and KriegBrückner, B. (eds.), Algebraic Foundations of Systems Specification, pp. 159–200. SpringerVerlag. Wirsing, M. (1990) Algebraic specification. Handbook of Theoretical Computer Science, Vol. B, pp. 675–788. Elsevier.