Functional Programming

Functional Programming

Functional Programming Sexy types in action Editor: Philip Wadler, University of Edinburgh; [email protected] Chung-chieh Shan Harvard University Cambridge MA 02138 USA The Hindley-Milner type system (Hindley 1969; Mil- tiating a polymorphic type. ner 1978) and its Damas-Milner inference algorithm E : τ (Damas and Milner 1982) for the λ-calculus (Church 8I (a does not escape) (2a) 1932, 1940) are widely adopted in modern functional pro- Λa: E : 8a: τ 0 gramming languages like Haskell and ML. The system E : 8a: τ 8E (2b) delicately balances power and tractability: many poly- Eτ : τ0[τ/a] morphic functions can be built, and many safety con- straints checked, without bogging down compilers in un- In the 8I rule above, the type variable a that is quantified decidability or programmers in verbosity. over must not escape—that is, it must not appear free in an undischarged typing assumption. When a type checker As programmers became familiar with the system's uses this rule bottom-up to check a universal type, it en- power, however, they also became frustrated by its lim- sures that the side condition on the type variable a holds itations. Much recent research thus explores the design by generating a fresh dummy type (termed an eigenvari- space beyond the Hindley-Milner-Damas system, termed able) and substituting it for a. That is, it α-converts the “sexy types” by Peyton Jones (2003). Two features of- bound variable a in 8a: τ. ten requested and implemented are higher-rank polymor- 0 phism and existential types. This annotated bibliography In the 8E rule above, τ [τ/a] denotes the capture- 0 summarizes these features (§1) and motivates them by avoiding substitution of τ for a in τ . The result of the enumerating their present-day applications (§2–3). substitution is said to subsume the universally quantified type 8a: τ0. The term syntax of the polymorphic typed λ-calculus 1 Polymorphic typed λ-calculus makes both of these rules explicit. For example, the polymorphic identity function is written as the term Λ A polymorphic value is one that can take multiple types. a: λx : a: x. It is given the type 8a: a ! a by the fol- We are concerned here with parametric polymorphism lowing derivation. (Strachey 1967), which corresponds to universal quantifi- [x : a] cation over types. To start, we review the typing rules for !Ix the polymorphic (or second-order) typed λ-calculus, also λx : a: x : a ! a 8I known as System F, invented independently by Girard Λa: λx : a: x : 8a: a ! a (1972; Girard et al. 1989) and Reynolds (1974, 1990). Because it is too verbose to mark every introduction and A function is created by discharging an assumption in elimination of a universal quantifier, we would like to the typing environment, and invoked by applying it to a make the rules in (2) implicit in terms, as follows. value of the appropriate argument type. E : τ E : 8a: τ0 [x : τ] 8I (a does not escape) 8E (3) · 0 · 0 E : 8a: τ E : τ [τ/a] · F : τ ! τ E : τ 0 !E (1) E : τ 0 We would also like to omit the argument type τ in the x FE : τ !I function term λx : τ. E. Unfortunately, this move makes λx : τ. E : τ ! τ0 type checking and type inference undecidable (Wells Universal quantification is introduced by generalizing the 1999). To recover decidability while preserving implicit type of a value, and eliminated by specializing or instan- polymorphism, the Hindley-Milner-Damas type system 1 Functional Programming trades off expressive power by restricting the rank of than 1. Type inference for rank-2 polymorphism is de- types to 1. The rank of a type is the maximum number of cidable without any help in the form of additional type function arrows to the left of which a universal quantifier annotations by the programmer, but is too complicated to appears. Formally, the following syntax defines a strati- be implemented so far (Kfoury and Tiuryn 1992; Kfoury fied language of rank-n types τn, where n ranges over the and Wells 1994). Type inference for arbitrarily higher- non-negative integers. rank polymorphism requires programmer annotations in order to be decidable. Several such systems have been τ0 ::= a τ0 ! τ0 proposed and implemented in production compilers such + + + τn 1 ::= 8a: τn 1 τn ! τn 1 as the Glasgow Haskell Compiler (Jones 1997; Odersky and Läufer 1996; Peyton Jones and Shields 2004; Le Bot- 0 A rank-0 type τ has no universal quantifier; it is called a lan and Rémy 2003). monotype. Hindley, Milner, and Damas's innovation is to require monotypes in (1), allow rank-1 types in (3), and add the “let” construct below for polymorphic assump- 2.1 Algebraic data types tions (Clément et al. 1986). Polymorphic functions can encode recursive data types [x : τ1] · (Reynolds 1983; Reynolds and Plotkin 1993; Böhm and · Berarducci 1985). For example, a singly-linked list of · (4) E : τ1 E0 : τ0 integers is defined in Haskell as Letx = 0 τ0 data IntegerList = Nil Cons Integer IntegerList; let x E in E : In the polymorphic typed λ-calculus, the only (closed) but we can encode this recursive data type as the poly- term of the type 8a: a ! a is the identity function. morphic function type In general, terms in the polymorphic typed λ-calculus ≡ 8 : ! ! ! ! : are always parametric, which intuitively means that a IntegerList l l (Integer l l) l value acts “uniformly” at all types it can take, regardless Informally speaking, a list of integers is equivalent to a of how universally quantified type variables are instanti- parametrically polymorphic function that maps a pair of ated. A function that negates booleans while leaving non- list constructors (one for the empty list and one for non- booleans unchanged would not be parametric. This prop- empty lists) to a list, for any (abstract) list data type. erty of uniformity, or type abstraction (Reynolds 1983), is usually formalized by introducing logical relations be- tween types and guaranteeing that, for example, a func- 2.2 Lazy functional state threads tion always maps related arguments to related results. The runST function, for running a stateful computation A semantic model of the polymorphic typed λ-calculus in a purely functional language like Haskell (Launchbury is said to be parametric if all of its values are paramet- and Peyton Jones 1994, 1995; Moggi and Sabry 2001), ric, so the only value in the model that has the type has the rank-2 type 8a: a ! a, for example, is the identity function. In other words, if f is a function from a to b, and g is a value of 8a: (8s: ST s a) ! a: type 8a: a ! a, then a parametric model guarantees that f ◦ g = g ◦ f . More generally, each polymorphic type The type variable s is a dummy that identifies the state gives rise to a parametricity law, an equation satisfied by thread being run: two operations that are performed any value expressible as a λ-term and any value in a para- within the same state thread automatically have their s metric model (Reynolds 1983; Wadler 1989, 2004). As variables unified by the type checker. The type for runST we will see below, useful parametricity laws tend to arise thus ensures that state does not leak or interfere with other from higher-rank polymorphism. stateful computations. The proof of this safety property uses parametricity at the type 8s: ST s a. 2 Higher-rank polymorphism 2.3 Generic (polytypic) programming Extensions to Hindley, Milner, and Damas's system al- A type a is a “traversable term” type if any traversal on low higher-rank polymorphism: types with rank higher the subterms of a can be “lifted” to a traversal on a itself. 2 Functional Programming For instance, if we have a traversal on list elements, then Here m is the monad in which impure computations take we have a traversal on lists: place. If we need to move from one monad m1 to another monad m2, then we need a function to map Value m1 map :: 8a: (a ! a) ! ([a] ! [a]) to Value m2. Such a function would have the following rank-2 (and higher-order polymorphic) type: This idea of lifting traversals from subterms to terms can be combined with a moderate amount of run-time 8m1:8m2:(8a:m1 a ! m2 a) ! (Value m1 ! Value m2): type-safe casting to achieve a form of generic program- ming (Lämmel and Peyton Jones 2003). The traversable The coproducts technique of monad combination (Lüth types a belong to a type class Term, which supports oper- and Ghani 2002) can also be viewed as a type of second- ations such as order kind whose values are manipulated by functions of higher rank. Given two well-behaved monads m1 and m , their coproduct Plus m m is a new monad, gmapT :: (8b: Term b ) b ! b) ! 2 1 2 where the type constructor Plus has the second-order kind (8a: Term a ) a ! a): (∗ ! ∗) ! (∗ ! ∗) ! (∗ ! ∗). Accompanying the type constructor Plus is a term combinator coprod, which has Note that this operation has a rank-2 type: the type vari- the rank-2 type able b is universally quantified over (with a type-class constraint) to the left of an arrow. 8m1: 8m2: 8n: (Monad m1; Monad m2; Monad n) ) If one wishes to avoid run-time type-casting, then (8a: m1 a ! n a) ! (8a: m2 a ! n a) ! one would need to manually write—or mechanically (8a: Plus m1 m2 a ! n a): generate—a slightly different traversal function for every type or type constructor over which generic processing is desired.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    8 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us