Academia.eduAcademia.edu

A Generic Framework for Genericity

Recently, generic programming becomes of a major interest in several programming paradigms. A recurrent idea to achieve genericity is to specify algorithms on their convenient data structure, and to allow these specifications to be instantiated onto a large number of neighboring data structures. Polytypic programming, shapely types and generic attribute grammars are generic programming methods related to this approach. A framework for generic programming is proposed to embed these methods. It consists in tools for automatic generation of morphisms between data structures, and for program composition. Thanks to this compositional approach, the complete specialization of generic programs could be advantageously delegated to a general and powerful mechanism of "symbolic composition", which performs deforestation and partial evaluation. 1 Introduction In several programming paradigms, generic programming is being emerging. Although this concept is not new, genericity currently...

A Generic Framework for Genericity Loc Correnson, Etienne Duris, Didier Parigot and Gilles Roussel INRIA Rocquencourt - France. Gilles Roussel is with Universite de Marne-la-Vallee. Abstract Recently, generic programming becomes of a major interest in several programming paradigms. A recurrent idea to achieve genericity is to specify algorithms on their convenient data structure, and to allow these speci cations to be instantiated onto a large number of neighboring data structures. Polytypic programming, shapely types and generic attribute grammars are generic programming methods related to this approach. A framework for generic programming is proposed to embed these methods. It consists in tools for automatic generation of morphisms between data structures, and for program composition. Thanks to this compositional approach, the complete specialization of generic programs could be advantageously delegated to a general and powerful mechanism of \symbolic composition", which performs deforestation and partial evaluation. 1 Introduction In several programming paradigms, generic programming is being emerging. Although this concept is not new, genericity currently raises a great interest in the programming and software engineering community. In this area, one of the recent issues is genericity according to the data structure. When an algorithm is speci ed on a general data structure, the notion of genericity appears with the possibility to reuse it in several contexts, says, onto particular data structures. A few years ago, Farrow et al. [7] devised a generic programming notion for attribute grammars [10, 14]. This genericity is based on the observation that any function f de ned by an attribute grammar on a type 2 could be instantiated on a type 1 . The only component needed, if it exists, is a function m that implements a morphism between terms of type 1 and terms of type 2 . The composition of this function m with the function f performs the instantiation process. This approach has been revisited [11, 15, 2] to enable automatic generation of the morphism m from a simple speci cation of correspondence relation between types. In this context, an ecient specialization process Submitted to the 3rd ACM SIGPLAN International Conference on Functional Programming (ICFP '98). consists in applying a transformation that eliminates intermediate data structures occurring in the composition. For attribute grammars, Ganzinger and Giegerich solved this general problem by introducing their descriptional composition algorithm [8, 1]. Using this technique, the construction of the intermediate representation of type 2 is discarded from the composition, and thus the original function f is transposed and actually specialized onto the type 1 . This problem of intermediate data structure elimination, usually called deforestation [17], has been widely studied in the functional programming community [12, 16, 13]. The comparison between functional and attribute grammar deforestation methods [6, 4] led us to propose a powerful deforestation method for functional programs, the symbolic composition [5]1 , which is based on descriptional composition. Since descriptional composition is an important component of the attribute grammar genericity framework, we have compared in [3] attribute grammar genericity with polytypic programming [9]. These methods seems to be complementary, and we propose in this article a general framework for genericity. This framework is based on function composition, automatic morphism generation and a general deforestation method. The major bene t for this approach is to really separate the application of a generic algorithm from the specialization of this instantiation. The rst problem is solved by morphism and composition, while the second is performed by a general and powerful deforestation method. Automatic morphism generation is still an open problem, even if methods already exist. The paper is organized as follows. Section 2 presents the general framework for genericity through the well-known example of uni cation algorithm. Section 3 presents two different methods to automatically generate morphisms, while section 4 illustrates the deforestation power for instantiation and specialization purposes. 2 Framework for Genericity Let us consider the general uni cation algorithm to illustrate our framework. Recall that it consists in comparing two terms t and t that contains variables and in computing a substitution  verifying ( t) = ( t ), if it exists. Although this problem is general, a particular implementation of the general algorithm is required for each type of the terms t and t . 0 0 0 1 This method deforests some functional programs for which existing functional methods fail. Specialization process performs the actual instantiation. To achieve genericity, we propose to specify it on the following well-suited type term : type term c a = var a j const c (list (term c a )) Type c allows to distinguish the di erent constructors in the term algebra, while type a allows to distinguish variables. Then, implementing the uni cation algorithm on this type term is natural and it corresponds to classical algorithmic presentations. The advantage of this approach is to ease the implementation and the readability of the generic speci cation. Indeed, everyone can understand the uni cation algorithm speci ed on this type. Let unify be the uni cation function. In order to use uni cation in practice, this uni cation function has to be composed with a morphism which instantiates the algorithm on a particular type. Suppose that uni cation is needed on a given type  . This implies that some morphism M from type  to type term exists and can be implemented in a function m. Since the uni cation gives a substitution which associates values of type term to variables, the inverse morphism m?1 is needed to translate back the result. The uni cation on  is instantiated by : unify  t t 0 = let  = unify (m t ) (m t 0 ) in x :(m ?1 ( x )) Then a classical deforestation method can be applied. After the deforestation of function unify  , the intermediate values of type ?term are no longer constructed and the functions m and m 1 are no longer used. Let g be the function unify deforested with m and m?1 , the function unify  becomes : unify  t t 0 = let 0 = g t t 0 in x :(0 x ) Another approach to this uni cation problem could be found in polytypic programming with PolyP [9]. In the example above, two parts appear. The rst one is a coupling process that produces a morphism between two types. This morphism is a function that translates a value into an intermediate representation; it could be composed with any program working on this intermediate representation. The second part applies a deforestation method in order to specialize such compositions into an instantiated algorithm. Consequently, the compositional framework for genericity is based on the three following key points : Generic programming is achieved by functions composition. These functions are divided into two kinds. These of the rst kind (e.g. unify ) implement generic algorithms on a convenient type. Functions of the second kind (e.g. m and m?1 ) implement translations between neighboring types. Morphism speci cation provides the actual genericity. Since it describes the translation between two types, it also gives the way to perform the algorithm instantiation. Most of morphisms involved in the compositions could be automatically derived, thanks to small speci cation in simple meta-languages. These metalanguages should not be super-languages of the original programming language used, in order to be reusable and quickly developed. Nevertheless, these morphisms could also be hand-written. Moreover, succesive morphisms can be composed. The speci ed compositions have to be improved. In fact, each generic function has to be customized with respect to its composition context. Rather than applying an ad-hoc method for each particular generic system, it is worthwhile to use a general deforestation or fusion method, that symbolically performs at one and the same time composition, elimination of intermediate values and partial evaluation. Let M be the morphism speci cation, C the morphism generation algorithm, alg the \generic" algorithm, m the morphism function generated, alg M the expected instanciated algorithm, and ? the programming environment. Then the framework for genericity is abstracted by the following gure : C m M; ? ) alg ; M; ? ) alg  m alg  m deforestation ) alg M alg  m ) alg M where  is the standard composition in the original language, and deforestation is a method like hylo [13], or Symbolic Composition [5]. 3 Morphism Generation In this section, two case studies of automatic morphism generation are presented. The rst one was inspired by polytypic programming [9], but has been totally revisited to match with our generic framework. The second case study was inspired by attribute grammar genericity [11, 15, 2], and is an illustration of cross-fertilization from di erent paradigms. For clarity, technical details and algorithm sketches are presented in annex A. 3.1 Compositional approach of polytypic programming Classically, in functional languages, functions are speci ed for a single given (polymorphic) type. However, most functions could be abstracted from any type. For example, the number of leaves in a tree and the length of a list are specied by very similar functions. To implement such generic functions, it is necessary to specify them on a type that can represent the structure of any value of any (polymorphic) type. We then propose the following type Poly : type Poly c o a = Sum c (Poly c o a ) j Prod (Poly c o a ) (Poly c o a ) j Par a j Obj o The type Poly is parameterized with three type variables. Let  be a given type. Intuitively, c is a type that identify the constructors of  , o is a type that identify other types that could appear in  (e.g. boolean, integer, etc.), and a is the polymorphic variable of type  . Thus, the classical type list type list a = nil j cons a (list a ) can be represented by the type (Poly c list o list a ) where : type c list = list cons j list nil type o list = list empty 2 An interesting point is that type Poly is de ned in the original functional language and does not require any special notation. The translation from type list to type Poly (resp. the backward translation) is performed by the function out list (resp. inn list ): 3.2 Previous section shows one way to generate a bijective morphism between any type  and type Poly . This section proposes another method to generate morphism between datastructures. The aim is to infer a { not necessarily bijective { morphism between two arbitrary types. Consider the following type representing a binary tree with one or two integers at each node : type clumsytree = node elements clumsytree clumsytree j nothing type elements = one int j two int int Now, consider the type  : type  = leaf j node1 ( ) ( ) j node2 ( ) ( ) A morphism between type clumsytree and type  can be implemented with the following function : let couplage t = match t with node (one a1 ) t1 t2 ! (node1 a1 (couplage t1 ) (couplage t2 )) node (two a1 a2 ) t1 t2 ! (node2 a1 a2 (couplage t1 ) (couplage t2 )) nothing ! leaf Two properties are veri ed by this morphism : type clumsytree is associated to ( ), and type int is associated to . It is possible to denote these two properties by the following relation : C or (tree ) = fclumsytree g C or ( ) = fint g Such a relation is called a correspondence relation between types clumsytree and  . The aim is now to automatically derive the function couplage from a given correspondence relation. In [11] we propose such an inference algorithm for attribute grammars. It is easy to translate it into functional programming, as described in annex B. The basic idea of this algorithm is to associate a subterm of type clumsytree to a sub-term of type  . Thus, the algorithm yields the following associations :  the term (node (one a1 ) t1 t2 ) must be associated to a term of type  , composed with a tuple of type ( ; ;  ). So it is associated to the term (node1 a1 t1 t2 ).  the term (node (two a1 a2 ) t1 t2 ) must be associated to a term of type  , composed with a tuple of type ( ; ; ;  ). So it is associated to the term (node2 a1 a2 t1 t2 ).  the term (nothing ) corresponds to a term of type  composed with nothing else. So it is associated to (leaf ). Then, from such an association, it is very easy to generate the expected function couplage . Sometimes, more complex associations have to be de ned. In [11], we show that it is not always possible to nd the associations, and we characterize these situations. A typical example is : type a = c1 n C or (a ) = fa g type n = c2 n n j c3 b C or (b ) = fb g type b = : : : out list x = match x with cons a b ! (Sum list cons (Prod (Par a ) (out list b ))) nil ! (Sum list nil (Obj list empty )) inn list p = match p with Sum list cons (Prod (Par a ) r ) ! (cons a (inn list r )) Sum list nil (Obj list empty ) ! (nil ) ! raise "not a list" These two morphisms out  and inn  can be automatically generated from every type  . Mutually recursive types and type compositions can also be automatically abstracted by morphism composition. Details can be found in annex A. Then a function that is independent from any type, but that depends on the data structure of its variable can be speci ed on type Poly . For instance, consider the functions size and atten ; they respectively calculate the number of Par occurrences in a value of type Poly , and their list : size x = match x with Sum c y ! (size y ) Prod y y ! (size y ) + (size y ) Par y !1 Obj z !0 atten x h = match x with Sum c y ! ( atten y h ) Prod y y ! ( atten y ( atten y h )) Par y ! (cons y h ) Obj z !h 0 0 Correspondence relation 0 0 Then, functions that compute the size and the leaves list on type tree (binary trees) and type list are obtained by the following compositions : type tree a = leaf a j node (tree a ) (tree a ) size list t = (size (out list t )) atten list t h = ( atten (out list t ) h ) size tree t = (size (out tree t )) atten tree t h = ( atten (out tree t ) h ) Applying deforestation will eliminate the construction of the intermediate value of type Poly , and will lead to the expected functions. For instance, for the type tree , deforestation leads to : size tree t = match t with node a b ! (size tree a ) + (size tree b ) leaf n ! 1 atten tree t h = match t with node a b ! ( atten tree a ( atten tree b h )) leaf n ! (cons n h ) The main advantage of type Poly is that a bijective morphism can be automatically derived from any (polymorphic) type. But this type is not the most natural to implement many algorithms. Actually, many algorithms need semantic information on values that are not necessary explicited by the structure of the type. For instance, it is dicult for the uni cation algorithm, to determine what and where are variables in the type Poly . 0 0 0 0 0 3 0 0 0 0 The problem is due to the fact that a can \derive" into an in nity of n which are not associated to anything by the correspondence relation. Moreover, in [11], we try to associate a term with a constructor instead of with a subterm. The general problem of \parsing" the leaves of a term like (node (one a1 ) t1 t2 ) with the constructors of a given type remains opened. Once again, this method fails when semantic information on types have to be taken into account in order to generate the morphism. Moreover, the morphism is often not bijective. Even if none of the two previously exposed methods are powerful enough to infer almost expected morphisms, they could yet be considered as tools to construct complex morphisms by composition of several simple ones. To instantiate the uni cation algorithm on trees where leaves are the variables, the two following morphisms are used : tree to term t = match t with node a b ! (const 1 [tree to term a ; (tree to term b )]) leaf n ! (var n ) term to tree t = match t with const 1 [a ; b ] ! (node (term to tree a ) (term to tree b )) var n ! (leaf n ) ! raise "not a tree !" Then, uni cation on trees is speci ed by : unify tree t t = (all unify term to tree tree to term ) t t The aim is now to transform this instantiation speci cation { the only one the programmer has to write { into a more specialized function. 0 4 Deforestation This section illustrates the power of deforestation in order to specialize instanciations of a \generic" program. After giving notations for the uni cation example, we show some critical steps of the complete deforestation process, for our deforestation method, namely the symbolic composition [5]. Applying deforestation : the rst step consists in spe- cializing the de nition of unify tree : unify tree t t = let s = (uni empty (tree to term t ) (tree to term t )) in x :(term to tree (s x )) Next, the composition of uni and tree to term is deforested into the function uni1 . In this function, many simplications have been performed, especially the partial evaluation of the function foldr : uni1 s t t = match (t ; t ) with (leaf x ; leaf x ) ! if x = x then s else (link s x (tree to term t )) ( ; leaf x ) ! (link s x (tree to term t )) (node a b ; node a b ) ! (uni1 (uni1 s b b ) a a ) Now the composition of link and tree to term is deforested into the function link1 . Thus, the function uni1 is updated into uni2 , and this leads to : unify tree t t = let s = (uni2 empty t t ) in x :(term to tree (s x )) Uni cation example : recall that a well suited type for 0 this problem is : type term c a = var a j const c (list (term c a )) Suppose now that the uni cation algorithm is standardly written for this simple type : unify : (term c a ) ! (term c a ) ! (a ! (term c a )) The expression (unify t t ) returns the substitution s if t and t are equals modulo s. The substitution s is given as a function from variables to terms. If the substitution does not exist, the function raises the exception No unif . The kernel of uni cation algorithm is implemented by the function uni : uni s t t = match (t ; t ) with (var x ; var x ) ! if x = x then s else (link s x t ) ( ; var x ) ! (link s x t ) (const c lt ; const c lt ) ! if c = c then foldr ((a ; a ):r :(uni r a a )) s (zip lt lt ) 0 0 0 0 0 0 0 else raise 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 uni2 s t t = match (t ; t ) with (leaf x ; leaf x ) ! if x = x then s else (link1 s x t ) ( ; leaf x ) ! (link1 s x t )) (node a b ; node a b ) ! (uni2 (uni2 s b b ) a a ) At this point, the substitution s still associates variables to terms, and not variables to trees. But further deforestation is possible, and the function uni3 will pre-calculate the composition of s with term to tree . At the end of the entire process, substitutions are physically constructed (in a list for instance). Then the substitution s is discarded and replaced by s1 , computed by the function uni4 . Consequently, the empty substitution is replaced by empty1 . This leads to : unify tree t t = let s1 = (uni4 empty1 t t ) in z :(s1 z ) 0 0 0 0 No unif 0 where (link s x t ) adds the substitution x = t to s if possible, and raises the exception No unif otherwise. We then have : unify t t = (uni empty t t ) where empty is the empty substitution. Now, to perform genericity, we have to specify for every type  a morphism from  to term . Since the uni cation returns a substitution, it is important to work with a bijective morphism. The function all unify instantiates unify with such a morphism de ned by the functions in : term ! tree and out : tree ! term . (all unify in out ) t t = let s = (unify (out t ) (out t )) in x :(in (s x )) 0 0 0 0 0 0 0 0 0 0 0 0 4 0 [6] Etienne Duris, Didier Parigot, Gilles Roussel, and Martin Jourdan. Attribute grammars and folds: Generic control operators. Rapport de recherche 2957, INRIA, August 1996. [7] Rodney Farrow, Thomas J. Marlowe, and Daniel M. Yellin. Composable attribute grammars: Support for modularity in translator design and implementation. In 19th ACM Symp. on Principles of Programming Languages, pages 223{234, Albuquerque, NM, January 1992. ACM press. [8] Harald Ganzinger and Robert Giegerich. Attribute coupled grammars. In ACM SIGPLAN '84 Symp. on Compiler Construction, pages 157{170, Montreal, June 1984. Published as ACM SIGPLAN Notices, 19(6). [9] P. Jansson and J. Jeuring. PolyP - a polytypic programming language extension. In 24th ACM Symp. on Principles of Programming Languages, 1997. [10] Donald E. Knuth. Semantics of context-free languages. Mathematical Systems Theory, 2(2):127{145, June 1968. Correction: Mathematical Systems Theory 5, 1, pp. 95-96 (March 1971). [11] Carole Le Bellec, Martin Jourdan, Didier Parigot, and Gilles Roussel. Speci cation and Implementation of Grammar Coupling Using Attribute Grammars. In Maurice Bruynooghe and Jaan Penjam, editors, Programming Language Implementation and Logic Programming (PLILP '93), volume 714 of Lect. Notes in Comp. Sci., pages 123{136, Tallinn, August 1993. Springer-Verlag. [12] E. Meijer, M. M. Fokkinga, and R. Paterson. Functional programming with bananas, lenses, envelopes and barbed wire. In Conf. on Functional Programming and Computer Architecture (FPCA'91), volume 523 of Lect. Notes in Comp. Sci., pages 124{144, Cambridge, September 1991. Springer-Verlag. [13] Y. Onoue, Z. Hu, H. Iwasaki, and M. Takeichi. A calculational fusion system HYLO. In In Proc. IFIP TC 2 Working Conference on Algorithmic Languages and Calculi, Le Bischenberg, France, February 1997. [14] Jukka Paakki. Attribute grammar paradigms | A high-level methodology in language implementation. ACM Computing Surveys, 27(2):196{255, June 1995. [15] Gilles Roussel. Algorithmes de base pour la modularite et la reutilisabilite des grammaires attribuees. PhD thesis, Departement d'Informatique, Universite de Paris 6, March 1994. [16] Tim Sheard and Leonidas Fegaras. A fold for all seasons. In Conf. on Functional Programming and Computer Architecture (FPCA'93), pages 233{242, Copenhagen, Denmark, June 1993. ACM Press. [17] Philip Wadler. Deforestation: transforming programs to eliminate trees. In Theoretical Computer Science, volume 73, pages 231{248, 1990. (Special issue of selected papers from 2'nd European Symposium on Programming). uni4 s1 t t = match (t t ) with (leaf x leaf x ) ! if x = x then s else (link2 s1 x t ) ( leaf x ) ! (link2 s1 x t )) (node a b node a b ) ! (uni4 (uni4 s b b ) a a ) 0 0 ; 0 ; 0 ; 0 0 ; 0 0 0 0 0 This deforestation process seems to be complex, but it only consists in multiple application of few rules. Moreover these simple rules are expressed independently from any functional language. We are using an attribute grammar based formalism enriched by dynamic constructions in order to take into account composition and partial evaluation into one single transformation, called symbolic composition. Thus, deforestation is the key tool to achieve genericity by composition, since a unique framework is available independently from any programming language. 5 Conclusion This article presents a general concept of generic programming, which is independent of any programming language. Instead of bringing di erent approaches into con ict, it expects large cross-fertilizations between di erent generic methods. Each of them has advantages and limitations, and o ers di erent { and complementary { kinds of genericity. In order to ease the cross-fertilizations it seems worthwhile to separate morphism speci cation from algorithm instantiation and specialization. Then, symbolic composition { or other deforestation method { is the basic tool which enables the specialization of an algorithm to be performed over new structures via morphisms speci cations. As soon as a deforestation method is available, many ways to achieve genericity can be developed quickly, easily and eciently. Besides, there exists certainly other generic programming and specializing methods that should be considered. From our point of view, it will be interesting to carry out some uni ed way to specify morphisms and to exhibit families of automatic or semi-automatic methods to generate these morphisms. References [1] John Boyland and Susan L. Graham. Composing tree attributions. In 21st ACM Symp. on Principles of Programming Languages, pages 375{388, Portland, Oregon, January 1994. ACM Press. [2] Loc Correnson. Genericite dans les grammaires attribuees. Rapport de stage d'option, E cole Polytechnique, 1996. [3] Loc Correnson. Programmation polytypique avec les grammaires attribuees. Rapport de DEA, Universite de Paris VII, September 1997. [4] Loc Correnson, Etienne Duris, Didier Parigot, and Gilles Roussel. Attribute grammars and functional programming deforestation. In Fourth International Static Analysis Symposium { Poster Session, Paris, France, September 1997. [5] Loc Correnson, Etienne Duris, Didier Parigot, and Gilles Roussel. Symbolic composition. Technical Report 3348, INRIA, January 1998. 5 Annex A Morphism generation for Poly The function out  is derived with :  = : : : j ck 1 : : : n j : : :  ` x i ; i ) t i out  x = match x with (ck x1 : : : xn ) ! (Sum ( ck ) (Prod t1 (Prod t2 : : : tn ))) ::: The following global-naming conventions are assumed: Gsum is the type that represents the constructors of every type  . Thus, the constructor c of type  is denoted by the constructor  c of type Gsum . Gobj is the type that represents values of any simple type appearing in some type  . For instance, if  contains integers and booleans : type Gobj = : : :  int int j  bool bool : : : Generation of inn  : Here, the inference rule notation is : t; t where  is the current type and ' the function to apply ; ' ` ; ' `  ) t; t 0 t ; (out  t ) ; ' ` ( ) ) 0 ( y = match y with t !t ! raise \error x ; (unshift  x ) new name 0 0 00 0 Then :  = : : : j ci i1 : : : in j : : : ; ' ` ik ) pik ; tik unshift  ' x = match x with (Sum ( ci ) (Prod p1i : : : pni )) ! (ci t1i : : : tni ) ::: where  is the current type, x is a term of type , and t is the term x translated from type  to type Poly . With these notations : ) (out  x ) And nally : parshift x = match x with (Par x ) ! x j ! raise \error inn  x = (unshift  parshift x )  ` x i ; i ) t i i = 1; 2  ` x; (1  2 ) ) (let (x1 ; x2 ) = x in (Prod t1 t2 )) Example  ` x;  ) (Obj (  x ))  ` y;  ) t  ` x; ( ) ) (shift (y :t ) (out  x )) 0 ) 0 t (Par x )  ` x; ( ) t ; (' t ) ; ' ` ( ) 0 ence rules. Their general scheme is : conditions ) ) ; ' `  ) (Obj (  u )); u  `  i ) ti ; ti i = 1; 2 ; ' ` (1  2 ) ) (Prod t1 t2 ); (t1 ; t2 ) Generation of out  : The algorithm is de ned by infer-  ` x; 0 0 Notice that all the morphisms have to be infered before the generation of types Gsum and Gobj . But since type Poly is a polymorphic type, this is not a problem for separate compilation. Types are de ned according to the following grammar :  ::= c1 1 j : : : j cn n constructors  ::= the polymorphic variable j  basic type j ( ) type composition j  type product ) ) where Par values are expected { useful for type compositions. For any type , the algorithm generates the pattern t of type Poly that represents a term of type , and its backward translation t of type  . out  is the function that implements a morphism between type  and type Poly ; inn  is the reciprocal function.  ` x;  conditions ; ' `  00 To illustrate how type composition is processed, let us consider the following example : type ower a = rose int a (tree ( ower a ))) It leads to : type Gobj = ower int int j : : : type Gcons = ower rose j tree node j tree leaf j : : : out ower x = match x with rose a b c ! (Sum ( ower rose ) (Prod ( ower int a ) (Prod (Par b ) (shift out ower (out tree x )))) inn ower x = unshift ower parshift x unshift ower f x = match x with Sum ower rose (Prod ( ower int a ) (Prod p r )) ! (rose a (f p ) (unshift tree inn ower r )) 0 The function shift is needed when type composition occurs. Actually, to compute the morphism from ( ) to Poly , a solution is : rst, compute the morphism from  to Poly ; second, compose this rst morphism with the one from ( ) to ( ). The second morphism is simply computed by the function shift , where f is supposed to be a morphism from  to Poly . shift f x = match x with (Par u ) ! (f u ) (Prod a b ) ! (Prod (shift f a ) (shift f b )) (Sum c u ) ! (Sum c (shift f u )) (Obj o ) ! (Obj o) 6 Annex B Correspondence relations From this association, the couplage function is easily inferred. Of course, many improvements could be done about correspondence relations. In the last step of the algorithm, the problem to solve is how to associate a closed tree of type 1 to some value of type 2 . The solution proposed here is quite simple by associating signatures to constructors. Commutativity, associativity, parsing may be taking into account to nd more complex associations. Let C or be a correspondence relation from type 1 to type 2 . We de ne the following objects : Components : each type consists of several components. Each constructor, each argument of a constructor and each occurrence of a (sub-)type are components. The correspondence relation links components from type 1 to components from type 2 . Key component : a component is a key one if it is linked by the correspondence relation. Neutral component : a component is a neutral one if it contains a key or neutral sub-component. Dead component : a component that contains neither key nor neutral is dead. Then, from a correspondence relation, it is possible to tag each component of a type. This de nes the Tag annotation. For instance, with the previous exemple (c; i stands for the i-th argument of constructor c) : Tag (nothing ) = key (tree12 ) Tag (one ) = neutral (elements ) Tag (one ; 1 ) = key ( ) Tag (node ) = key (tree12 ) Tag (node ; 1 ) = neutral (elements ) Tag (node ; 2 ) = key (tree12 ) etc : To generate the morphism, it is necessary to look for closed -terms. A closed term is a nite term, whose root and leaves are tagged by key, and that contains only neutral internal constructors (dead components are discarded). For instance, (node (two a1 a2 ) t1 t2 ) is closed. But (node e1 t1 t2 ) is not closed, since e1 is tagged by neutral. And (node (one a1 ) (nothing) t2 ) is nor closed, since the constructor nothing replaces an internal key component. It is easy to generate the closed-terms by a transitive closure (or x-point) algorithm. The idea is to recursively replace a neutral leaf of a non-closed term by any sub-term of type  . Of course, there exist conditions to insure the termination of the algorithm. See [11] for more details. Now, the notion of signature is needed. The signature of a term is the list of its root and leaves key -tags. For instance, with the previous example, the closed-terms and their signature are : node (one a1 ) t1 t2 :   !  node (two a1 a2 ) t1 t2 :   ! nothing : () !  Signature is extended to constructors of type 2 . Thus, the signature of the constructor node1 is the same as of the closed term (node (one a1 ) t1 t2 ) one. Then, each closedterm of type 1 is associated with one constructor of type 2 that has the same signature. With the previous example, the following association is obtained : node (one a1 ) t1 t2 ) node1 node (two a1 a2 ) t1 t2 ) node2 nothing ) leaf 7