Generic Level Polymorphic N-Ary Functions

Generic Level Polymorphic N-Ary Functions

Generic Level Polymorphic N-ary Functions Guillaume Allais University of Strathclyde Glasgow, UK [email protected] Abstract unifier (Section5), we can design a good representation of n- Agda’s standard library struggles in various places with n- ary function spaces (Section6) which empowers us to write ary functions and relations. It introduces congruence and generalised combinators (Sections7 and8) usable with mini- substitution operators for functions of arities one and two, mal user input. We then see how the notions introduced to and provides users with convenient combinators for manip- tackle our original motivations can be mobilised for other ef- ulating indexed families of arity exactly one. forts in generic programming from an arity-generic zipWith After a careful analysis of the kinds of problems the unifier (Section 9.2) to a direct style definition of printf (Section 9.3). 1 can easily solve, we design a unifier-friendly representation This paper is a literate Agda file ; we discuss some of the of n-ary functions. This allows us to write generic programs more esoteric aspects of the language in AppendixA. acting on n-ary functions which automatically reconstruct the representation of their inputs’ types by unification. In 2 N-ary Combinators... for N up to 2 particular, we can define fully level polymorphic n-ary ver- Agda’s standard library relies on propositional equality de- sions of congruence, substitution and the combinators for fined as a level polymorphic inductive family. It hasone indexed families, all requiring minimal user input. constructor (refl) witnessing the fact any value is equal to itself. CCS Concepts • Theory of computation → Type struc- tures; • Software and its engineering → Domain spe- data_ ≡_{ A : Set a}( x : A): A ! Set a where cific languages; Software libraries and repositories. refl: x ≡ x Keywords Dependent types, Arity-generic programming, As one would expect from a notion of equality, it is con- Universe polymorphism, Agda gruent (i.e. for any function equal inputs yield equal outputs) and substitutive (i.e. equals behave the same with respect ACM Reference Format: to predicates). Concretely this means we can write the two Guillaume Allais. 2019. Generic Level Polymorphic N-ary Functions. following functions by dependent pattern-matching on the In Proceedings of the 4th ACM SIGPLAN International Workshop equality proof: on Type-Driven Development (TyDe ’19), August 18, 2019, Berlin, Germany. ACM, New York, NY, USA, 13 pages. https://doi.org/10. cong:( f : A ! B) ! x ≡ y ! fx ≡ fy 1145/3331554.3342604 cong f refl= refl 1 Introduction subst:( P : A ! Set p) ! x ≡ y ! Px ! Py For user convenience, Agda’s standard library has accumu- subst P refl px = px lated a set of equality-manipulating combinators of vary- However we quickly realise that it is convenient to be able ing arities (Section2) as well as a type-level compositional to use congruence for functions that take more than one Domain Specific Language to write clean types involving argument and substitution for at least binary relations. The indexed families of arity exactly one (Section 3.1). None of standard library provides binary versions of both of these these solutions scale well. By getting acquainted with the functions: Permission to make digital or hard copies of all or part of this work for cong2 :( f : A ! B ! C) ! personal or classroom use is granted without fee provided that copies x ≡ y ! t ≡ u ! fxt ≡ fyu are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights cong2 f refl refl= refl for components of this work owned by others than the author(s) must be honored. Abstracting with credit is permitted. To copy otherwise, or subst2 :( R : A ! B ! Set p) ! republish, to post on servers or to redistribute to lists, requires prior specific x ≡ y ! t ≡ u ! Rxt ! Ryu permission and/or a fee. Request permissions from [email protected]. subst P refl refl pr = pr TyDe ’19, August 18, 2019, Berlin, Germany 2 © 2019 Copyright held by the owner/author(s). Publication rights licensed If we want to go beyond arity two we are left to either to ACM. define our own ternary, quaternary, etc. versions of cong ACM ISBN 978-1-4503-6815-5/19/08...$15.00 https://doi.org/10.1145/3331554.3342604 1The source code is available at https://github.com/gallais/nary 14 TyDe ’19, August 18, 2019, Berlin, Germany Guillaume Allais and subst, or to awkwardly chain the ones with a lower arity that a given predicate P holds of all the elements of a list. to slowly massage the expression at hand into the shape we It has two constructors which each bear the same name as want. Both of these solutions are unsatisfactory. their counterparts in the underlying data: nil ([]) states that all the elements in the empty list satisfy P and cons (_::_) Wish We would like to define once and for all two func- states that P holds of all the elements of a non-empty list if tions cong and subst of respective types (pseudocode): n n it holds of its head and of all the elements in its tail. congn :(f : A1 !···! An ! B) ! data All( P : A ! Set p): List A ! Set( a t p) where ≡ !···! ≡ ! a1 b1 an bn []: All P [] fa 1 ··· an ≡ fb 1 ··· bn _::_: Px ! All P xs ! All P (x :: xs) substn :(R : A1 !···! An ! Set r) ! a1 ≡ b1 !···! an ≡ bn ! Some of our examples require the introduction of Any, Ra 1 ··· an ! Rb 1 ··· bn the other classic predicate lifting on list. It takes a predicate and ensures that it holds of at least one element of the list at 3 Invariant Respecting Programs hand. Either it holds of the first one and we are given a proof A key feature of dependently typed languages is the ability (here) or it holds of a value somewhere in the tail (there). to enforce strong invariants. Inductive families [8] are es- data Any( P : A ! Set p): List A ! Set( a t p) where sentially classic inductive types where one may additionally here: Px ! Any P (x :: xs) bake in these strong invariants. As soon as the program- ! mer starts making these constraints explicit, they need to there: Any P xs Any P (x :: xs) write constraints-respecting programs. Although a lot of programs are index-preserving, users need to be painfully 3.1.1 Quantifiers explicit about things that stay the same (i.e. the index being We have two types of quantifiers: existential and univer- threaded all across the function’s type) rather than being sal. As they are meant to surround the indexed expression able to highlight the important changes. they are acting upon, we define them as essentially pairs of matching opening and closing brackets. The opening one 3.1 Working With Indexed Families is systematically decorated with a mnemonic symbol: 9 for The standard library defines a set of handy combinators to existential quantification, Π for explicit dependent quantifica- talk about indexed families without having to manipulate tion and 8 for implicit universal quantification. Additionally their index explicitly. These form a compositional type-level we use angle brackets for existential quantifiers and square Domain Specific Language [11] (DSL): each combinator has brackets for universal ones, recalling the operators diamond a precise semantics and putting them together builds an and box of modal logic. overall meaning. Existential Quantifier In type theory, existential quan- A typical expression built using this DSL follows a fairly tifiers are represented as dependent pairs. We introduce Σ, simple schema: a combinator acting as a quantifier for the a dependent record parameterised by a type A and a type index (Section 3.1.1) surrounds a combination of pointwise family P. It has two fields proj for a value of type A and proj liftings of common type constructors (Section 3.1.2), index 1 2 for a proof of type (P proj ). We can build and pattern-match updates (Section 3.1.3), and base predicates. This empowers 1 against pairs using the constructor _,_ and we can project us to write lighter types, which hide away the bits that are either of the pair’s components simply by using its field’s constant, focusing instead on the key predicates and the name. changes made to the index. Before we can even talk about concrete indexed families, record Σ (A : Set a)( P : A ! Set p): Set( a t p) where describe these various combinators, and demonstrate their constructor _,_ usefulness, we need to introduce the data the families in field proj1 : A our running examples will be indexed over. We pick List the proj2 : P proj1 level polymorphic type of lists parameterised by the type of The existential quantifier for indexed families is defined their elements: it is both well-known and complex enough as a special case of Σ; it takes the index Set implicitly. to allow us to write interesting types. 9h_i :{ A : Set a}( P : A ! Set p) ! Set( a t p) data List( A : Set a): Set a where 9h P i = Σ _ P []: List A Using 9h_i we can write our first statement about an _::_: A ! List A ! List A indexed family: from the existence of a list such that P holds The most straightforward non-trivial indexed family we of all its elements, we can construct a list of pairs of elements can define over List is the predicate lifting All which ensures and proofs that P holds for that value.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    13 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