Good Advice for Type-directed Programming Aspect-oriented Programming and Extensible Generic Functions Geoffrey Washburn Stephanie Weirich University of Pennsylvania {geoffw,sweirich}@cis.upenn.edu ABSTRACT of type-directed combinators to “scrap” this boilerplate. For Type-directed programming is an important idiom for soft- example, L¨ammeland Peyton Jones’s Haskell library pro- ware design. In type-directed programming the behavior of vides a combinator called gmapQ that maps a query over programs is guided by the type structure of data. It makes an arbitrary value’s children returning a list of the results. it possible to implement many sorts of operations, such as Using gmapQ it becomes trivial to implement a type-directed serialization, traversals, and queries, only once and without function, gsize, to compute the size of an arbitrary value. needing to continually revise their implementation as new gsize :: Data a => a -> Int data types are defined. gsize x = 1 + sum (gmapQ gsize x) Type-directed programming is the basis for recent research into “scrapping” tedious boilerplate code that arises in func- However, this line of research focused on closed type- tional programming with algebraic data types. This research directed functions. Closed type-directed functions require has primarily focused on writing type-directed functions that that all cases be defined in advance. Consequently, if the are closed to extension. However, L¨ammel and Peyton Jones programmer wanted gsize to behave in a specialized fashion recently developed a technique for writing openly extensible for one of their data types, they would need to edit the type-directed functions in Haskell by making clever use of definition of gmapQ. type classes. Unfortunately, this technique has a number of The alternative is to provide open type-directed functions. limitations. L¨ammel and Peyton Jones developed a method for writing We present an alternate approach to writing openly exten- openly extensible type-directed functions, via clever use of sible type-directed functions by using the aspect-oriented pro- Haskell type classes [13]. While their technique provides the gramming features provided by the language Aspectml. Our extensibility that was previously missing, there are caveats: solution not only avoids the limitations present in L¨ammel and Peyton Jones technique, but also allows type-directed • It only allows open extension at compile-time, pre- functions to be extended at any time with cases for types venting the programmer from indexing functions by that were not even known at compile-time. This capability dynamically created/loaded data types. is critical to writing programs that make use of dynamic • It is not possible to openly extend type-directed func- loading or runtime type generativity. tions with special cases for existential data types [14], nested data types [3], or generalized algebraic data 1. INTRODUCTION types (gadts) [23]. Each of these sorts of data types pose problems for constraint resolution. Type-directed programming (tdp) is an invaluable idiom for solving a wide class of programming problems. The • Each open type-directed function used introduces a behavior of a type-directed function is guided by the type typing constraint into the environment, which for poly- structure of its arguments. Serialization, traversals, and morphic functions is captures as part of the function’s queries can all be implemented via tdp, with the benefit that type. This makes it difficult to use these functions as they need only be written once and will continue to work first-class values because their types may be too con- even when new data types are added as the program evolves. strained to be used as arguments to other functions. tdp has become a popular technique for eliminating bor- ing “boilerplate” code that frequently arises in functional Because of these restrictions, L¨ammel and Peyton Jones programming with algebraic data types [11, 12, 8, 7]. The retain their old tdp mechanism as a fallback when openly goal in this research has been to develop easy-to-use libraries extensible type-directed functions cannot be used. Providing distinct mechanisms for open and closed tdp significantly increases the complexity of tdp for the user. Additionally, it may not be easy for a user unfamiliar with type inference Permission to make digital or hard copies of all or part of this work for for type classes to understand why an extension to an open personal or classroom use is granted without fee provided that copies are type-directed function fails type-check. not made or distributed for profit or commercial advantage and that copies We present an alternate approach to openly extensible bear this notice and the full citation on the first page. To copy otherwise, to tdp using the aspect-oriented programming (aop) features republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. provided by the language Aspectml. Aspect-oriented pro- Copyright 2006 ACM X-XXXXX-XX-X/XX/XX ...$5.00. gramming languages allow programmers to specify what com- putations to perform as well as when to perform them. For example, aop in AspectJ [10] makes it easy to implement a (kinds) k ::= * kind of types profiler that records statistics concerning the number of calls | k1 -> k2 function kinds to each method. The what in this example is the computa- (polytypes) s ::= <a[:k]> r tion that does the recording and the when is the instant of (ρ-types) r ::= t monotypes | s -> s higher-rank function time just prior to execution of each method body. In aop | pc pt pointcut terminology, the specification of what to do is called advice (pointcut type) pt ::= (<a[:k]> s1 ~> s2) and the specification of when to do it is called a pointcut des- (monotypes) t ::= a type variables ignator. A set of pointcut designators and advice organized | T type constructors to perform a coherent task is called an aspect. | Unit unit We, with with Daniel S. Dantas and David Walker, devel- | String strings oped Aspectml as part of our research on extending aop to | Int integers | t -> t functions functional languages with parametric polymorphism [5]. In 1 2 | (t1, ... ,tn) tuples a language with parametric polymorphism, it is difficult to | [t] lists write advice when a function may be used at many types. | t1 t2 type application It is also common to simultaneously advise functions with (terms) e ::= x term variables disparate types. To address both of these issues, we found | C data constructors runtime type analysis necessary for writing expressive advice. | () unit | " ... " strings However, we began writing more complex examples in | i integers Aspectml, and we found that not only was runtime type | e1 e2 application analysis necessary for expressive advice, but that advice | let d in e end let declarations was necessary for expressive type-directed functions. In | (fn p=>e) abstraction particular, aspects enable openly extensible tdp. We use | case e of p=>e pattern matching advice to specify what the behavior of a specific type-directed | typecase t of t=>e typecase function should be for a newly defined type, or combination | #f[:pt]# pointcut set | any any poincut of types, and when a type-directed function should use the | (e1, ... ,en) tuples case provided for the new type. | [e1, ... ,en] lists Furthermore, we believe that our entirely dynamic mech- | e:s annotation anism for aop is critical to this expressiveness. Nearly all (patterns) p ::= _ wildcard other statically typed aop languages have a compile-time | x variable binding step called “weaving” that fixes the when. In contrast, de- | C data constructors | () unit cisions concerning when are made entirely at runtime in | " ... " strings Aspectml. Consequently, not only does tdp in Aspectml | i integers improve extensibility when writing programs, but also while | p1 p2 application the programs are running. For example, it is possible to | [p1, ... ,pn] tuples safely patch Aspectml programs at runtime or manipulate | (p1, ... ,pn) lists data types that did not exist at “compile-time”. | p:s annotation (trigger time) tm ::= before Our contributions in this paper include: | after | around • examples of tdp in Aspectml. (declarations) • examples of how runtime advising is essential to the expressiveness of type-directed functions. d ::= val p = e value binding | fun f <a[:k]> (p)[: s] = e recursive functions • a comparison of our technique with other approaches | datatype T [: k] = C:s data type def to openly extensible tdp. | advice tm e <a[:k]> (p ,p ,p )[: s] = e 1 1 1 3 2 advice def | case-advice tm e1 (x:t1,p1,p2)[:t2] = e2 In the next section, we introduce aop in Aspectml via examples. In Section 3, we explain and show examples of tdp Figure 1: AspectML syntax. Optional annotations are in in Aspectml. In Section 4, we show how aop in Aspectml math brackets. can be used to openly extend type-directed functions. In Section 5, we provide a more detailed comparison with related research. Finally, in Section 6, we discuss future directions an arbitrary member of this sequence. We use a typewriter and summarize our results. font to indicate Aspectml programs or fragments. Italicized text is used to denote meta-variables. We assume the usual conventions for variable binding and α-equivalence of types 2. THE ASPECTML LANGUAGE and terms. We begin by introducing the general design of Aspectml. The type structure of Aspectml has three layers: polytypes, Aspectml is a polymorphic functional, aspect-oriented lan- ρ-types, and monotypes. Unless, otherwise stated when we guage descended from the ml family of languages. The syntax refer to “types” in Aspectml we mean monotypes. Polytypes for a fragment of Aspectml is given Figure 1. It is most are normally written <a:k> r where a:k is a list of binding similar to Standard ml [19], but occasionally uses OCaml or type variables with their kinds and r is a ρ-type.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages12 Page
-
File Size-