A Categorical Programming Language

Tatsuya Hagino

Doctor of Philosophy University of Edinburgh Author’s address:

Tatsuya Hagino Data Processing Center Kyoto University Kyoto 606 Japan

Abstract

A theory of data types and a programming language based on category theory are presented.

Data types play a crucial role in programming. They enable us to write programs easily and elegantly. Various programming languages have been developed, each of which may use different kinds of data types. Therefore, it becomes important to organize data types systematically so that we can understand the relationship between one data type and another and investigate future directions which lead us to discover exciting new data types.

There have been several approaches to systematically organize data types: algebraic specification methods using algebras, domain theory using complete partially ordered sets and type theory using the connection between logics and data types. Here, we use category theory. Category theory has proved to be remarkably good at revealing the nature of mathematical objects, and we use it to understand the true nature of data types in programming.

We organize data types under a new categorical notion of F, G-dialgebras which is an extension of the notion of adjunctions as well as that of T -algebras. T -algebras are also used in domain theory, but while domain theory needs some primitive data types, like products, to start with, we do not need any. Products, coproducts and exponentiations (i.e. function spaces) are defined exactly like in category theory using adjunctions. F, G-dialgebras also enable us to define the natural number object, the object for finite lists and other familiar data types in programming. Furthermore, their symmetry allows us to have the dual of the natural number object and the object for infinite lists (or lazy lists).

We also introduce a functional programming language in a categorical style. It has no primitive data types nor primitive control structures. Data types are declared using F, G-dialgebras and each data type is associated with its own control structure. For example, natural numbers are associated with primitive recursion. We define the meaning of the language operationally by giving a set of reduction rules. We also prove that any computation in this programming language terminates using Tait’s computability method.

A specification language to describe categories is also included. It is used to give a formal semantics to F, G-dialgebras as well as to give a basis to the categorical programming language we introduce.

Acknowledgements

The greatest thanks go to Professor Rod Burstall who, first of all, accepted me as a Ph. D. student, then, supervised me during my Ph. D. study and, further, gave me an opportunity to continue working in Edinburgh. He gave me not only useful advices but also much-needed mental support. I would also thank to his wife, Sissi Burstall, who invited me to their house often and made my stay in Edinburgh very pleasant.

I am also grateful to Professor Reiji Nakajima for having encouraged me to come to Edinburgh and to Professor Heisuke Hironaka for having helped me to solve the financial problem for studying in Edinburgh.

Many lectures I attended in the first year enlightened me a lot: domain theory, operational semantics, denotational semantics, algebraic specification, category theory, and so on. I did not know what category theory really is before I came to Edinburgh. Thanks to Andrzej Tarlecki, Edmund Robinson and John Cartmell for having helped me to overcome the initial difficulty of category theory. John Cartmell also helped me a lot through discussions in the early stage of the thesis. I am also in debt to Furio Honsell who introduced me to Tait’s method for proving normalization theorems of lambda calculi when I stuck in the normalization proof of CPL. Many other people in Edinburgh helped me with their comments and through discussions. I would especially like to thank Bob McKay and Paul Taylor for reading the early drafts and discovering some disastrous mistakes.

This thesis is written using LaTEX on a Sun workstation and printed by an Apple LaserWriter. I would like to thank George Cleland and Hugh Stabler for providing wonderful computing facilities and software to Laboratory of Foundation of Computer Science.

My Ph. D. study at the University of Edinburgh has been funded by the Educational Project for Japanese Mathematical Scientists, Harvard University, by the Overseas Research Students Award and by the Science and Engineering Research Council Research Fellowship.

Contents

1 Introduction 1

1.1 Backgrounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.1 Algebraic Specification Methods . . . . . . . . . . . . . . . . . . 2 1.1.2 Domain Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2 Basic Category Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.3 Development of Categorical Data Types . . . . . . . . . . . . . . . . . 7 1.4 In This Thesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.5 Comparison with Other Works . . . . . . . . . . . . . . . . . . . . . . . 15

2 Categorical Specification Language 17 2.1 A Functorial Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2.2 Signatures of Categorical Specification Language . . . . . . . . . . . . . 26 2.3 Structures of Categorical Specification Language . . . . . . . . . . . . . 31 2.4 Functorial Calculus (revisit) . . . . . . . . . . . . . . . . . . . . . . . . 32 2.5 Sentences and Satisfaction Relation of Categorical Specification Language 38 2.6 Free Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3 Categorical Data Types 44 3.1 What are Categorical Data Types? . . . . . . . . . . . . . . . . . . . . 44 3.2 Data Type Declarations in Categorical Data Types . . . . . . . . . . . 53 3.3 Examples of Categorical Data Types . . . . . . . . . . . . . . . . . . . 56

3.3.1 Terminal and Initial Objects . . . . . . . . . . . . . . . . . . . . 56 3.3.2 Products and CoProducts . . . . . . . . . . . . . . . . . . . . . 57 3.3.3 Exponentials . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.3.4 Natural Number Object . . . . . . . . . . . . . . . . . . . . . . 60 3.3.5 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.3.6 Final Co-Algebras (Infinite Lists and Co-Natural Number Object) 63 3.3.7 Automata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 3.3.8 Obscure Categorical Data Types . . . . . . . . . . . . . . . . . 69

3.4 Semantics of Categorical Data Types . . . . . . . . . . . . . . . . . . . 70 3.5 Existence of Left and Right . . . . . . . . . . . . . . . . . . . . . . . . 74

4 Computation and Categorical Data Types 78 4.1 Reduction Rules for Categorical Programming Language . . . . . . . . 79 4.2 An Example of using Reduction Rules . . . . . . . . . . . . . . . . . . 92 4.3 Well-Definedness and Normalization Theorem for Reduction Rules … 96 4.4 Properties of Computable Objects . . . . . . . . . . . . . . . . . . . . . 108 4.5 Reduction Rules for Full Evaluation . . . . . . . . . . . . . . . . . . . . 112

5 Application of Categorical Data Types 115 5.1 An implementation of Categorical Programming Language . . . . . . . 115 5.2 Typed Lambda Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . 120 5.3 ML and Categorical Programming Language . . . . . . . . . . . . . . . 124

Conclusions 128

Bibliography 131

Chapter 1

Introduction

This is an exploration of data types through category theory. It is an attempt to achieve better understanding of data types, their uniform classification, and discovery of a new world of data types. Data types have been with us since the very first programming languages. Even some machine languages now have some concept of data types, but early programming languages had only a fixed number of data types, like integers, reals and strings, and/or a fixed number of data type constructors, like array constructors and record constructors. When we gradually realized how important data types were, programming languages started having richer and richer data types. A number of programming languages now allow us to define our own data types. Some might even say that the richer they are, the better the programming languages are. Programming languages can be classified by the way how they handle data types.

There is no question about the importance of data types. Much research in this area has produced various kinds of data types, so varied that one cannot capture them all. We now need to systematically organize data types. We want to know the connection between one data type and another. We want to know the reason why those data types are with us and while some other data types are not. After getting a clear view of data types, we might find the future direction to discover other important data types.

There have been already some attempts to organize data types. We can name some of the important ones: Domain theory is one, algebraic specification is another and type theory is one where a lot of research is going on at the moment. In this thesis, we will present yet another attempt to organize data types. We do so by using category theory. We call our data types Categorical Data Types (or CDT for short).

One might ask “Why category theory?” Category theory is known as highly abstract mathematics. Some call it abstract nonsense. It chases abstract arrows and diagrams, proves nothing but about those arrows and diagrams, rarely talks about what arrows are for and often concepts go beyond one’s imagination. However, when this ‘abstract nonsense’ works, it is like magic. One may discover a simple theorem actually means very deep things and some concepts beautifully unify and connect things which are unrelated before.

In ordinary mathematics, whether we are aware or not, we are in the world of set theory. Mathematics has been so well developed with set theory that we can hardly do anything without it. Therefore, it is very natural that semantics of programming languages is generally based on set theory. Note that it is often said that most of programming languages do not have set theoretic semantics and, therefore, domain theory has been developed, but this does not contradict with “semantics based on set theory”, because domain theory itself is based on set theory. A domain is a set with certain properties.

Set theory is a powerful tool, but sometimes this power disfigures beautiful objects so that we cannot directly see their natural properties. For example, in set theory it is not easy to see either the duality between injective and surjective functions or the duality between cartesian products and disjoint sums. It is in category theory that these dualities come out clearly. Category theory concentrates on the outer behaviour of objects. It does not care what is in an object, whereas set theory is all about what is in an object. It is interesting to know that seeing from the outside reveals the nature of an object more naturally than seeing its inside. For example, one of the most important concepts discovered by category theory is adjunction (or adjoint situation), which is strikingly simple but very beautiful and unifies various concepts under the same name.

Our slogan is: “category theory can provide a better and more natural understanding of mathematical objects than set theory”, so we use it to guide our tour around the world of data types. Note that we do not mean to abandon set theory by this. We will still heavily rely on it, but our intuition should not be obstructed by it.

1.1 Backgrounds

1.1.1 Algebraic Specification Methods

Algebraic specification methods were first developed to describe what programs do. They are not like operational semantics or denotational semantics. These semantics also describe what programs do but in a different way. They describe it by giving meaning to each part of programs. They need to know how programs are written, that is, they need actual codes. Whereas, algebraic specification methods never talk about how programs are implemented. They describe their behaviour abstractly viewing from outside.

This abstract view point, seeing from outside, led to the discovery of abstract data types (see e.g. [Goguen, Thatcher and Wagner 78]). It is interesting to know that algebraic specification methods were started to describe programs but it also developed a theory of data types. Since algebraic specification methods try to describe things from an outside point of view, they cannot talk about the concrete nature of data types which programs handle. Therefore, the data types also needed to be abstracted and, thus, abstract data types have been developed. We may divide algebraic specification methods into two: specification of data types and specification of programs.

[figure: Specification; of Programs; Specification of Data Types; Algebraic Specification]

It is the former, specification of data types, that concerns us in this thesis.

Algebraic specification methods got their method of describing data types from abstract algebras in mathematics. Mathematicians have been using abstract algebras for about a century. Abstract algebras are only concerned with concrete real algebras insofar as they satisfy some laws. For example, a set with a binary operation is a group when the operation is associative, there is an identity and every element is invertible. A real set and a real operation can be anything, integers and +, general linear matrixes and their multiplication, and so on. Any theorem established for general groups can be applied to any real groups. There are various kinds of abstract algebras: groups, rings, fields, and so on. Those abstract algebras can be presented uniformly by universal algebras. Algebraic specification methods use a many-sorted version of universal algebras.

Naïvely speaking, an algebraic specification is a triple (S, Σ, E), where S is a set of sorts, Σ is a S^{∗} × S-indexed set of operations and E is a set of equations over Σ. For example, in an algebraic specification language CLEAR [Burstall and Goguen 80, Burstall and Goguen 82] a specification of lists may be as follows.

     constant List =
         theory
            sorts element, list
            opns nil : list
                 cons : element, list -> list
                 head : list -> element
                 tail : list -> list
            eqns all e : element, l : list, head(cons(e,l)) = e
                 all e : element, l : list, tail(cons(e,l)) = l
          endth

S is { element, list }, Σ_{list} is { nil }, Σ_{listelement} is { head }, and so on. E consists of the two equations above.

There are several problems about this specification as we will see immediately after we say what a specification means. An algebraic specification (S, Σ, E) defines a class of many sorted algebras each of which, say A, consists of an S-sorted set |A| and functions f_{A}: |A|_{s_{1}} × … × |A|_{s_{n}} ⟶ |A|_{s} for each f ∈ Σ_{s_{1}...s_{n}s} which satisfy the equations in E.

The first problem of the above specification is that not only lists satisfy it but also many of other data types as well. There is actually no way to make it describe only lists so long as we stick to first order methods. We need something of second order. The way algebraic specification methods usually obtain this is to put data constraints. We rely on the categorical fact that the initial algebra is unique up to isomorphism. In this case, we put a data constraint onto the sort ‘list’, but not to ‘element’ because if we put a data constraint onto ‘element’ then the ‘element’ sort would be empty.

The second problem is that ‘head’ and ‘tail’ are partial functions. The specification does not say what is ‘head(nil)’ or what is ‘tail(nil)’. In order to fix this problem, we have to introduce, for example, error algebras or go into partial algebras.

The third problem is that although we put a data constraint on ‘list’ it is not immediately obvious that ‘nil’ and ‘cons’ can construct all the lists. Some algebraic specification languages do distinguish these constructors from the others.

The fourth problem is about the sort ‘element’. We actually need it as a parameter. When we use this specification, ‘element’ denotes a particular data type defined by another specification and we need a way to plug in any specification of ‘element’ into this specification. Actually, CLEAR has this facility. ‘List’ can be defined as ‘procedure’ taking parametrized type ‘element’. However, this new specification no longer corresponds to a class of algebras but to something one level higher.

Many other problems there might be, but most of them have been solved in one way or another. The important point we would like to make is that the naïve idea of

algebraic specification = universal algebra

does not work well and we have to put a lot of other ideas into algebraic specification methods. One might wonder why so many complications are needed to define everyday objects like lists.

In CDT, we stick to the very simple relation

categorical data type = F, G-dialgebra

F, G-dialgebras can be seen as an extension of universal algebras (see section 3.1). We do not need to introduce meta arguments or any other complicated ideas into CDT in order to define lists or other basic data types.

1.1.2 Domain Theory

Domain theory was started with denotational semantics [Stoy 77, Scott 76]. In order to give denotational semantics to programs, we need several domains to which the denotations are mapped. Those domains are often interwoven and recursively defined. The most famous example of this is the following D.

D ≅ D → D

This domain D was necessary to give denotational semantics to the untyped lambda calculus. In general, we would like to solve the following domain equation:

D ≅ F (D)

where F (D) is a domain expression involving D.

Though domains are mathematical objects and not necessarily representable in computers, the idea of recursively defined data types has been adopted into several programming languages. For example, we can have a domain L for lists of A elements by solving^{1}

L ≅ 1 + A × L,

and in the original version of ML [Gordon, Milner and Wordsworth 79], we could define the data type for lists just like the same.

     abstype 'a list = unit + 'a # 'a list
         with ...

On the other hand, some domains cannot be represented in the same way. For example, we can have a domain I for infinite lists of A elements by solving

I ≅ A × I_{⊥}

where I_{⊥} is the lifting of I by adding the new least element, but we cannot define infinite lists in ML in a similar way.

Comparing with algebraic specification methods, in domain theory we can define data types easily and there is no complication of parametrized data types, but we have some difficulty of defining operations over data types. In algebraic specification methods we define operations together with data types, but in domain theory we have to define them using the isomorphisms of domain equations.

If an algebraic specification (S, Σ, E) has no equational constraints (i.e. E = ∅), the initial algebra can be given by solving the following domain equations.

|A|_{s} ≅ ∑_{f∈Σ_{s_{1}...sns}} |A|_{s_{1}} × … × |A|_{s_{n}}

By this connection, we can see the possibility of combining algebraic specification methods and domain theory together. Actually, data types in the current Standard ML [Milner 84, Harper, MacQueen and Milner 86] are defined in this mixed fashion (see also section 5.3).

Categorically, we can go the other way round. If F (D) is a covariant functor, the initial fixed point of F (D) can be characterized as the initial F -algebra. A F -algebra is a categorical generalization of an ordinary algebra. The main idea we borrow from domain theory is this connection between initial fixed points and initial algebras.

1We have to say what kind of domains we are dealing with. Let us say in this thesis that a domain is a complete partially ordered set with the least element and a function between domains needs to be continuous and strict.

After becoming familiar with category theory, one can notice the dual connection between final fixed points and final co-algebras. People rarely talked about them until recently [Arbib and Manes 80]. One of the reasons is that co-algebras are not so popular and another reason is that final fixed points are often the same as initial fixed points in domain theory. However, in CDT we will use this dual connection as well. Final co-algebras give us some very intersting data types like infinite lists. We defined infinite lists by the initial fixed point of

I ≅ A × I_{⊥}

Actually, what we were doing using the lifting I_{⊥} is to get the final fixed point of

I ≅ A × I.

1.2 Basic Category Theory

This section is to roughly introduce some categorical concepts we will use in the rest of this thesis. The author refers to category theory text books like [Mac Lane 71], [Arbib and Manes 75] and [Lambek and Scott 86] for a more detailed account of category theory.

A category C is given by

⋄ a collection of objects |C|,

⋄ for any pair of objects A and B, a collection Hom_{C}(A, B) of morphisms from

domain A to codomain B, (we write f: A → B for f ∈ Hom_{C}(A, B)) ⋄ for any objects A, B and C, an operation called composition denoted by ‘∘’ from

Hom_{C}(B, C) × Hom_{C}(A, B) to Hom_{C}(A, C) which is associative,

(f ∘ g) ∘ h = f ∘ (g ∘ h)

⋄ for any object A, an identity morphism I_{A}: A → A such that for any f: B → A

and any g: A → C

I_{A} ∘ f = f and g ∘ I_{A} = g

Two objects A and B are called isomorphic if there are two morphisms f: A → B and g: B → A such that

f ∘ g = I_{B} and g ∘ f = I_{A}.

f and g are called isomorphisms.

The opposite category C^{op} of a category C is defined by reversing the direction of all the morphisms in C.

Hom_{C^{op}}(A, B) = Hom_{C}(B, A)

We may write C^{op} morphism f^{op}: A → B for C morphism f: B → A.

The product category C × D of a category C and a category D is given as ⋄ a C × D object is ⟨A, B⟩ for a C object A and a D object B ⋄ a C × D morphism from ⟨A, B⟩ to ⟨A′, B′⟩ is ⟨f, g⟩ for a C morphism f: A → B

and a D morphism g: A → B.

A covariant functor F from a category C to a category D (we write F: C → D) is given by

⋄ associating a D object F (A) for every C object A

⋄ associating a D morphism F (f): F (A) → F (B) for every C morphism f: A → B

such that

F (I_{A}) = I_{F (A)} and F (f ∘ g) = F (f) ∘ F (g)

A contravariant functor is defined in a similar way except that F (f): F (B) → F (A).

A natural transformation α from a covariant functor F: C → D to a covariant functor G: C → D (we write α: F →^{·} G) is given by

⋄ associating a D morphism α_{A}: F (A) → G(A) for every C object A such that for any C morphism f: A → B the following diagram commutes.

[figure: F (A); α_{A}; G(A); F (f); G(f); F (B); α_{B}; G(B)]

When every α_{A} is an isomorphism, we call α natural isomorphism.

Two functors F: C → D and G: D → C are called adjoints if there exists a natural isomorphism

ψ_{A,B}: Hom_{D}(F (A), B) ⟶^{≅} Hom_{C}(A, G(B)).

F is called the left adjoint functor of G and G is called the right adjoint functor of F. We also call ψ_{A,B} (or its inverse ψ_{A,B}^{−1}) factorizer or mediating morphism.

1.3 Development of Categorical Data Types

The motivation of CDT was to adopt the categorical way of defining data types into specification languages. Anybody educated using set theory has quite a shock when he first sees the way category theory works. It gives a totally different point of view to things which are familiar. Things which were vaguely connected suddenly are fitted into systematic places. It seems that the nature of things is finally revealed.

There are many beautiful concepts discovered through category theory, but here we concentrate only one of them, namely adjunction (or adjoint situation). In [Mac Lane 71], one will find many equivalent forms of the definition of adjunction (we gave one of them in section 1.2). One may be first at a loss for chosing the definition. Adjunction is so versatile that it can be seen in a number of different forms and it is sometimes difficult to understand it if one sticks to a particular form of the definition. The form is not important if the spirit is understood. Adjunction can be regarded as a property of two functors or because of the unique correspondence between two functors it can be seen as defining one of them from the other. It is the latter which is important to us because it is a typical way of defining things in category theory. Let us see an example.

Using set theory, we can define what the product of two sets is, what the product of two groups is, what the product of two topological spaces is, and so on. Each definition is obviously deferent from the others but all of them are called by the same name, product. Why is that so? Is there any common property which all the different kinds of products should satisfy? Can we give the general definition of product? Category theory can give an affirmative answer to these questions. The categorical definition of products is

For object A and B, the product A × B is an object such that there are two morphisms

π_{1}: A × B ⟶ A and π_{2}: A × B ⟶ B

and for any given two morphisms

f: C ⟶ A and g: C ⟶ B

there is a unique morphism h: C ⟶ A×B such that the following diagram commutes.

[figure: A; A × B; B; π_{1}; π_{2}; C; f; g; h]

It is easily shown that any two objects satisfy this definition are isomorphic. We may write ⟨f, g⟩ for h.

This definition is general enough to cover the definition of products for sets, groups, topological spaces, and so on. We no longer need to define products for each individual case.

The generality should not be bound only in mathematics. Why should it not equally be appropriate to the definition of products in programming languages? The product data type of type A and type B is usually defined as a type of records whose first component is of type A and the second one is of type B, but this definition is like one in set theory. It assumes too much about how elements of data types are represented. It is not acceptable as an abstract description of the product data type. If the product data type is defined as an abstract data type, how can we present it?

We can directly adopt the categorical definition of products. There are five ingredients in the definition.

1. two given objects A and B,
2. the object A × B we are defining,
3. two morphisms π_{1}: A × B ⟶ A and π_{2}: A × B ⟶ B,
4. ⟨f, g⟩: C ⟶ A × B for f: C ⟶ A and g: C ⟶ B, and
5. the commutative diagram.

We may write these down as follows

object A × B is π_{1}: A × B ⟶ A π_{2}: A × B ⟶ B ⟨f, g⟩: C ⟶ A × B for f: C ⟶ A and g: C ⟶ B

where π_{1} ∘ ⟨f, g⟩ = f π_{2} ∘ ⟨f, g⟩ = g π_{1} ∘ h = f ∧ π_{2} ∘ h = g ⇒ h = ⟨f, g⟩

end object.

(∗)

Can we call this a categorical definition of the product data type constructor? Although this is an exact copy of the categorical definition, it has somehow lost the spirit of category theory; its beauty; its simplicity. The categorical definition of products we gave is in a disguised form of adjunction. The definition could have been sufficient to just say that the product functor is the right adjoint of the diagonal functor. The previous definition expands this into plain words so that there are a lot of duplications. One of them is that the type of ⟨ , ⟩ can be deduced from the type of π_{1} and π_{2}. If f and g has the same type as π_{1} and π_{2} except replacing A×B by C, ⟨f, g⟩ is a morphism from C to A × B. Another duplication is that the commutative diagram can also be deduced from the rest. There are no other trivial ways to make diagrams involving π_{1}, π_{2}, f, g and ⟨f, g⟩. Therefore, the definition of product data types can be written simply as

object A × B is π_{1}: A × B ⟶ A π_{2}: A × B ⟶ B

end object.

This supplies the minimal information to get back to (∗). Now, we have to use the fact that A × B is defined by adjunction (it was not necessary in (∗)). Let us indicate this by saying it is a right object as well as declaring ⟨ , ⟩.

right object A × B with ⟨ , ⟩ is π_{1}: A × B ⟶ A π_{2}: A × B ⟶ B

end object

This is the declaration of the product data type constructor in CDT (except for minor changes).

Let us examine the generality and simplicity of this declaration mechanism through examples. Let us try exponentials B^{A}. The functor •^{A} is defined as the right adjoint functor of • × A. The definition in CDT is

right object B^{A} with curry( ) is eval: B^{A} × A ⟶ B

end object

We can derive the usual definition of exponentials from this definition. First, the type of curry( ) should be

\frac{f: C × A ⟶ B}{curry(f): C ⟶ B^{A}} .

The type of f is obtained from the type of ‘eval’ just replacing B^{A} by C. The commutative diagram which curry(f) gives can be obtained by connecting

[figure: B^{A} × A; eval; B; and; C × A; f; B]

by curry(f): C ⟶ B^{A}. The only way to connect them together results

[figure: C × A; curry(f) × A; f; B^{A} × A; B; eval]

The morphism denoted by curry(f) is the unique one which makes this diagram commute. Thus, we recovered the ordinary definition of exponentials.

We said ‘right object’ for products and exponentials. It is natural to think that we also have ‘left object’ as dual. The dual of products are coproducts. Let us define them in CDT.

left object A + B with [ , ] is ν_{1}: A ⟶ A + B

ν_{2}: B ⟶ A + B

end object

The type of [ , ] can be obtained from the type of ν_{1} and ν_{2}.

f: A ⟶ C g: B ⟶ C
[f, g]: A + B ⟶ C

Note that [f, g] goes from A + B to C not the other way round as it would be if it were a right object. The name ‘left object’ came from the fact that A + B is in the left hand side of ⟶. Remember that A × B was in the right hand side of ⟶ for ⟨ , ⟩.

A natural way of connecting f and g with ν_{1} and ν_{2} by [f, g] gives us the ordinary commutative diagram which [f, g] should satisfy.

[figure: A; A + B; B; ν_{1}; ν_{2}; C; f; g; [f, g]]

We demonstrated that we can express basic categorical constructs in CDT. Those constructs, or data types, are primitives in ordinary programming languages. Can we declare more familiar data types? In fact, the ‘left object’ declaration gives all those which can be defined by algebraic methods with no equations. ‘Without equations’ seems that we cannot define much, but actually it gives us all the important data types of ordinary programming languages. For example, natural numbers can be defined as

left object nat with pr( , ) is zero: 1 ⟶ nat succ: nat ⟶ nat

end object

This is very much like a specification of natural numbers in algebraic specification methods except that we do not have the predecessor function or plus or times and that we have something called pr( , ). From analogy of the types of [ , ] and ⟨ , ⟩, the type of pr( , ) should be

\frac{f: 1 ⟶ C g: C ⟶ C}{pr(f, g): nat ⟶ C} .

We also obtain the diagram characterizing ‘nat’ as we did for products and others.

[figure: 1; zero; nat; succ; nat; f; pr(f, g); pr(f, g); C; C; g]

This is exactly the definition of ‘nat’ being a natural number object in category theory and it is well-known that we can define all the primitive recursive functions using pr( , ). For example, the addition function can be defined by

add =^{def} eval ∘ ⟨pr(curry(π_{2}), curry(succ ∘ eval)) ∘ π_{1}, π_{2}⟩.

As another example, we give the definition of lists in CDT. It is

left object list(A) with prl( , ) is nil: 1 ⟶ list(A) cons: A × list(A) ⟶ list(A)

end object

The type of prl( , ) is

\frac{f: 1 ⟶ C g: A × C ⟶ C}{prl(f, g): list(A) ⟶ C} .

The diagram is

[figure: 1; list(A); A × list(A); B; A × B; nil; cons; f; prl(f, g); I_{A} × prl(f, g); g]

Remember that our definition of lists in CLEAR had ‘head’ and ‘tail’, but we do not declare them here. We can define them by prl( , ).

head =^{def} prl(ν_{2}, ν_{1} ∘ π_{1})  : list(A) ⟶ A + 1
tail =^{def} [ν_{1} ∘ π_{2}, ν_{2}] ∘ prl(ν_{2}, ν_{1} ∘ ⟨π_{1}, [cons, nil]⟩)  : list(A) ⟶ list(A) + 1

‘Without equations’ is not a disadvantage to define everyday data types.

By the connection between initial fixed points and F -algebras, we can define the initial fixed point D of a covariant functor F (X) as follows.

left object D with ψ( ) is α: F (D) ⟶ D

end object

α gives one direction of the isomorphism between D and F (D), and ψ( ) gives unique arrows.

[figure: F (D); α; D; F (ψ(f)); ψ(f); F (A); f; A]

We have been using ‘left object’ more than ‘right object’, but they are dual and there are equally as many right objects as left objects. Just they are not familiar in ordinary programming languages. For example, the following definition gives the data type for infinite lists.

right object inflist(A) with fold( , ) is hd: inflist(A) ⟶ A tl: inflist(A) ⟶ inflist(A)

end object

This gives the final fixed point of I ≅ A × I.

We have devised, based on category theory, a simple way of defining data types. The next question is whether we can adopt this method into ordinary programming languages. The answer is negative. Although what we can define in this way is far less than what we can define using algebraic specification languages with equations, we still have some strange things that can be defined in this way. Let us see an example. We defined list(A) as a parametrized data type but in fact it is a functor.

list(f): list(A) ⟶ list(B)

for a morphism f: A ⟶ B is often called map function. In LISP it is ‘MAPCAR’ and in ML it is ‘map’. The general declaration mechanism of CDT allows us to define the left and right adjoint functors of list(A) which could not exist in the world of programming. We need to put a restriction to prevent these objects. The restriction will come out of a notion of computability in our setting. Interestingly, it turns out the category should be

cartesian closed + initial fixed points + final fixed points

We might see the similarity between this and the connection of lambda calculus and cartesian closed categories.

By putting this computability restriction, we can regard CDT as not only a device of defining data types but also a programming language. We program in a categorical fashion; there are no concrete data but morphisms; programs are also morphisms; there are no variables in programs. The computation in this language is reduction from morphisms to canonical ones. For example, we can reduce

add ∘ ⟨succ ∘ zero, succ ∘ zero⟩ ⇒ succ ∘ succ ∘ zero

which corresponds to the calculation of 1 + 1 = 2.

We summerize the characteristics of CDT as follows.

1. CDT uses categorical characterization of data types. We do not need to say things explicitly. All the equations are automatically generated for definitions.

2. CDT needs no primitive data types. Ordinary programming languages (e.g. PAS-CAL, LISP, ML) have primitive data types: natural numbers, lists, records, and so on, but CDT does not. They can be defined. Thus, CDT is analogous to algebraic specification methods where we can specify them as well. However, algebraic specification methods cannot specify higher order data types (i.e. function spaces or exponentials in a categorical term) nor can they specify products without using equations.

3. CDT can not only define products without explicitly mentioning equations but also can define exponentials.

4. CDT is symmetric in the sense that we can define initial algebras (or initial fixed points) as well as final co-algebras (or final fixed points).

5. Algebraic specification methods use initiality implicitly and do not use the unique homomorphisms between the initial algebras and the others, whereas CDT has explicit access to the unique morphisms. This gives the power of programming without going though equational characterization as it is necessary in algebraic specification methods.

6. Domain theory does not use the initiality explicitly either. The reason for this is that recursion in ordinary programming languages provide all the power of programming.

7. CDT defines functors. Functors are thought to be parametrized data types. Algebraic specification methods usually introduce parametrization later, but in CDT functorial behaviour of parametrized data types is treated at the base level.

1.4 In This Thesis

The theory of categorical data types is divided into three: Categorical Specification Language, Categorical Data Types and Categorical Programming Language.

Categorical Programming Language

Categorical Data Types

Categorical Specification Language

Chapter 2 is about Categorical Specification Language (CSL for short). CSL is a specification language. It is an extension of ordinary algebraic specification languages. Whereas algebraic specifications specify algebras, it specifies categories. In order to specify categories, CSL has to handle functors, natural transformations and factorizers (or mediating morphisms). A CSL signature declares some functor names and their types (i.e. variances), some natural transformation names and their types and some factorizer names and their types. A CSL sentence is a conditional equation of functors, natural transformations and factorizers. A CSL model is a category equipped with functors, natural transformations and factorizers which have right types as are specified in the signature and which satisfy the sentences.

Chapter 3 gives the main idea of Categorical Data Types. The difference between CSL and CDT is that whereas CSL declares functors, natural transformations and factorizers separately and connects them by sentences, CDT declare them together in a style of adjoint declarations. The semantics of CDT will be given informally in terms of F, G-algebras and formally in terms of CSL. There are some examples of data types we can define in CDT.

Chapter 4 is about Categorical Programming Language (CPL for short). CPL is a functional programming language which adopts the categorical declaration mechanism of data types from CDT. In order to define the notion of computation in CPL, we have to put some restrictions to CDT. We will introduce the notion of elements and canonical elements and present reduction rules to reduce elements to their equivalent canonical elements. We will also prove that any reduction in CPL terminates using Tait’s computability method.

Each of those three languages, CSL, CDT and CPL, characterizes a category of data types in different ways.

Syntax  Semantics
CSL Signature and Sentences  Models
CDT Adjoint Declarations  Freeness and Co-Freeness
CPL Restricted Adjoint Declarations Operational

In chapter 5, we will investigate the real consequences of our study in CDT. Section 5.1 is about an implementation of CPL as a real programming language. Section 5.2 is about the connection between CDT and typed lambda calculi, and finally in section 5.3 we will attempt to extend ML incorporating the CDT data type declaration mechanism.

1.5 Comparison with Other Works

Systematic studies of data types have already been carried out by various people in various contexts: ADJ in the context of initial algebras [Goguen, Thatcher and Wagner 78], Plotkin, Smyth and Lehmann in the context of domains [Lehmann and Smyth 81, Smyth and Plotkin 82] and Martin-Löf in the context of type theory [Martin-Löf 79]. This thesis is about a study of the same subject in the context of category theory. We do not try to extend the traditional approaches as Parasaya-Ghomi did for algebraic specification methods to include higher order types [Parasaya-Ghomi 82], nor do we try to unify two approaches together like [Dybjer 83], but we just directly use categorical methods of defining things.

Categorical Programming Language in chapter 4 might resemble Categorical Abstract Machine (CAM) by Curien [Curien 86], but he is only interested in cartesian closed categories whereas CPL deals with a class of different categories. Moreover, the reduction rules in CPL is systematically generated for products, coproducts, exponentials, natural numbers, and so on. We do not give any special reduction rules for any data types we define. CPL can be seen as

CPL = CAM + initial data types + final data types.

Actually, CAM can be absorbed into ‘initial data types’ and ‘final data types’, so in CPL we do not need to start with a particular set of reduction rules for cartesian closed categories. CPL has an ability to define cartesian closed categories and the introduction of data types also gives the control structure over those data types. Here is another slogan: “control structures in programming languages come out of the structure of data types”.

Data Types  Control Structures
boolean ↔ if statement
disjoint union ↔ case statement
natural number ↔ primitive recursion, for statement
product ↔ pairing
function space ↔ function call

Barr and Wells uses sketches in [Barr and Wells 85] to describe algebras categorically. It is more powerful than ordinary algebraic specification methods because sketches can use any kind of limits whereas algebraic specification methods uses only products. It is interesting to investigate CSL by sketches.

Categorical Specification Language

CDT can be seen from various points of view and can be presented in many ways. In this chapter, we present it as a specification language for categories (we call the specification language Categorical Specification Language or CSL for short). This is not the way originated, and it is difficult to recognize natural properties of data types in this way. We will give an alternative and more intuitive definition of CDT in chapter 3. However, the aim of CSL is to give mathematically rigorous background for the more intuitive presentation of CDT.

In applicative functional programming languages like ML, it is natural to see that their data types and functions form a category; each data type is an object; each function is a morphism; we have an identity function; and two functions can be composed in a usual way. We can also treat other programming languages including procedural ones semantically as defining domains and functions, and we can see that they form a category. These categories associated with programming languages reflect the characteristics of the programming languages. Thus, the study of data types can be carried out by examining these categories. CSL is a specification language for these categories.

Usually, a category is given by defining what an object consists of (e.g. a set for Set, the category of sets) and what a morphism between objects is (e.g. a set function for Set), but this is not the way CSL works. We are trying to understand a category in an abstract manner; we do not say what an object is; instead, we specify how it is constructed through its relationship among other objects. We saw in chapter 1 an ML data type for lists and it was a parameterized data type. We can now see it as a data type constructor; given a data type it constructs a new data type for the lists of the given data type. Categorically, constructors of objects are functors and they provide structures for categories. Remember that a cartesian closed category is a category with three functors, the terminal (constant) functor, the product functor and the exponential functor. Thus, CSL specifies a category equipped with some functors. Because the properties of functors are often described in terms of their interaction with natural transformations and factorizers (e.g. the binary product functor is explained with two natural transformations, π_{1} and π_{2}, and factorizer ⟨ , ⟩), CSL also specifies natural transformations and factorizers.

Let us make a comparison with algebraic specification languages like CLEAR [Burstall and Goguen 80, Burstall and Goguen 82]. An algebraic specification consists of declarations of some sorts and some operations on these sorts. Sorts are their data types. A model of an algebraic specification is a many-sorted algebra. On the other hand, a CSL specification consists of declarations of some functors, some natural transformations between them and some factorizers. Functors correspond to sorts, and natural transformations and factorizers correspond to operations. A model of a CSL specification is a category equipped with some functors, some natural transformations between them and some factorizers. It is abstract in the sense that the specification does not distinguish between equivalent categories (an algebraic specification does not distinguish isomorphic algebras). Note that, in general, the various models of a specification are not equivalent (e.g. not all the cartesian categories are equivalent).

As CSL specifies functors, the treatment of parametrized data types is different from algebraic specification languages. It specifies one level higher objects. The concept of parameterized data types and how to combine them play very essential roles in algebraic specification languages, but parameterized data types are treated in their meta-level (one level higher than the level treating algebras), that is specifications themselves are parameterized rather than dealing with parameterized sorts in specifications. In CSL, on the other hand, parameterized data types are the basic objects in specifications. In one specification, several parameterized data types can be declared and their relationship is directly specified. Therefore, combining specifications does not play as important a role as it does in algebraic specification languages.

Our goal in this chapter is to define the specification language CSL. In section 2.1, we will introduce several notations for dealing with functors which will be necessary later. In section 2.2, we will define the CSL signatures and in section 2.3 the CSL structures. The definition of CSL sentences and the CSL satisfaction relation will be in section 2.5 which follows section 2.4 in which we will introduce expressions involving natural transformations and factorizers. Finally, in section 2.6 we will show that there is an initial CSL structure for each CSL theory.

2.1 A Functorial Calculus

Before giving the definition of CSL signatures, we will look at some aspects of functors. This will be a kind of a functorial calculus though not as abstract as [Kelly 72] is. [Kelly 72] develops a calculus of combining functors as we will do in this section, but for the purpose of solving the coherence problems, and he treats many variable functors quite extensively. However, he does not say much about mixed variant functors which we are interested in. We will also generalize variances to include free-variance and fixedvariance for uniform treatment.

Functors are very much like ordinary functions except that functors have variances. Let F be a unary functor C → C and G be a binary functor C × C → C. Then, we can combine them to get more complex functors:

G(F (X), Y) F (G(X, F (Y))) G(F (X), G(X, Y)) …

We call them functorial expressions. Of course, not every such expression denotes a functor. For example, G(X, X) is not a proper functor if G is covariant in one argument and contravariant in the other. It is a functor if G is covariant in both arguments or contravariant in both arguments, or if G does not depend on one of the arguments.

In order to cope with these situations uniformly, we introduce two new variances: fixedvariance and free-variance. We say that a functor F (X) is fixed-variant in X if F is not functorial in X, that is, F maps objects to objects, but not morphisms. We also say that a functor F (X) is free-variant in X if F does not depend on X. Therefore, when G: C × C → C is covariant in the first argument and contravariant in the second, G(X, X) is a fixed-variant functor.

Let us introduce the symbols for variances.

Definition 2.1.1: Let Var be the set of variances {+, −, ⊥, ⊤}: + for covariance, − for contravariance, ⊥ for free-variance and ⊤ for fixed-variance. []

The next definition is extending the notion of opposite categories.

Definition 2.1.2: Let C be a category.

1. C^{+} is C itself.

2. C^{−} is the opposite category of C.

3. C^{⊥} is the category which has only one object and only one morphism (i.e. the identity of the one object). We may call the category one point category.

4. C^{⊤} is the category which has the same objects as C but no morphisms except identities. []

In this way, we can regard the variances as functions mapping categories to categories (i.e. Cat → Cat, where Cat is the category of (small) categories) or we can even regard them as a monoid acting on Cat.

Definition 2.1.3: ⟨Var, •⟩ is a commutative monoid with unit +, where the monoid operation •: Var × Var → Var is defined by the following table.

\begin{matrix}• & ⊥ & + & − & ⊤ \\ ⊥ & ⊥ & ⊥ & ⊥ & ⊥ \\ + & ⊥ & + & − & ⊤ \\ − & ⊥ & − & + & ⊤ \\ ⊤ & ⊥ & ⊤ & ⊤ & ⊤ \end{matrix}

[] Proposition 2.1.4: ⟨Var, •⟩ is a monoid acting on Cat, that is, C^{u•v} = (C^{u})^{v} for any u, v ∈ Var. Proof: We have to show (C^{−})^{−} = C (i.e. the opposite of opposite is itself) and so on, but they are trivial. []

Since we will deal with many variable functors and they are functors from products of categories C × ⋯ × C to a category C, Var action for product categories should be investigated.

Proposition 2.1.5: Var action on Cat distributes over products, that is, for any categories C and D

(C × D)^{u} ≅ C^{u} × D^{u}.

Proof: In case u is −, it says that the opposite of the product category is isomorphic to the product of the opposite categories and it is the case because ⟨f, g⟩^{op}: ⟨A, B⟩ → ⟨C, D⟩ ⟺ ⟨f, g⟩: ⟨C, D⟩ → ⟨A, B⟩ ⟺ f: C → A and g: D → B ⟺ f^{op}: A → C and g^{op}: B → D ⟺ ⟨f^{op}, g^{op}⟩: ⟨A, B⟩ → ⟨C, D⟩. The other cases are trivial. []

We need one more preparation before talking about mixed variant functors. The category C^{⊤} can be embedded into C^{+} as well as into C^{−} and they themselves are embedded into C^{⊥}, that is we have the following embedding functors.

C^{+}
↙ ↖
C^{⊥}  C^{⊤}
↖ ↙
C^{−}

We introduce a partial order on Var to respect these embeddings.

Definition 2.1.6: ⊑ is a partial order on Var such that ⊥ ⊑ + ⊑ ⊤ and ⊥ ⊑ − ⊑ ⊤. []

From the definition, it is clear that

Proposition 2.1.7: If u ⊑ v, there is an embedding functor e_{u,v}: C^{v} → C^{u}. []

Now we can start talking about mixed variant functors and their calculus. As a function is associated with an arity (simply a natural number), a mixed variant functor over a particular category C is associated with a varity which is a sequence of variances. For example, binary functor G: C × C → C which is contravariant in the first argument and covariant in the second is a functor with a varity −+.

Definition 2.1.8: A mixed variant functor F of varity v_{1} … v_{n} is a (covariant) functor from C^{v_{1}} × ⋯ × C^{v_{n}} to C. []

When we are given a Var^{∗}-indexed set Γ of primitive mixed variant functors, where F ∈ Γ_{v_{1}...v_{n}} is a functor of varity v_{1} … v_{n}, we would like to establish how to combine these primitive functors and get more complex functors like H(G(X, Y), F (X)).

Firstly, we extend the action of variances on categories to that on functors. For example, from a contravariant functor F: C^{−} → C we get a covariant functor F^{−}: C → C^{−} as

F^{−}(f: A → B) =^{def} F (f^{op}: B → A).

Definition 2.1.9: For a functor F: C → D,

1. a functor F^{+}: C^{+} → D^{+} is F itself,

2. a functor F^{−}: C^{−} → D^{−} is given by F^{−}(A) = A for an object A in C and F^{−}(f^{op}) = F (f)^{op} for a morphism f in C,

3. a functor F^{⊥}: C^{⊥} → D^{⊥} is the identity functor since both C^{⊥} and D^{⊥} are the one point category, and

4. a functor F^{⊤}: C^{⊤} → D^{⊤} has the same object mapping as F but no morphism mapping.

[figure: F: C → D; F^{⊤}: C^{⊤} → D^{⊤}; F^{−}: C^{−} → D^{−}; F^{⊥}: C^{⊥} → D^{⊥}; []]

This definition is forced from the definition of C^{u}, so Var action has more structure.

Proposition 2.1.10: For a functor F: C → D, (F^{u})^{v} = F^{u•v}. Proof: We have to check this for all the combinations of u and v. For example, (F^{−})^{⊤} = F^{⊤} is true because F^{−} only changes the mapping of morphisms but (F^{−})^{⊤} forgets it. []

We have the two propositions which give us the basis for combining mixed variant functors.

Proposition 2.1.11: For functors F: C^{u_{1}} × ⋯ × C^{u_{n}} → C^{v_{1}} × ⋯ × C^{v_{m}} and G: C^{v_{1}} × ⋯ × C^{v_{m}} → C (i.e. varity v_{1} … v_{m}), G ∘ F is a functor of C^{u_{1}} × ⋯ × C^{u_{n}} → C (i.e. varity u_{1} … u_{n}).

[figure: C^{u_{1}} × ⋯ × C^{u_{n}}; F; C^{v_{1}} × ⋯ × C^{v_{m}}; G; C]

Proof: Trivial from the definition of composition of functors. [] Proposition 2.1.12: For functors F_{1}: C^{u_{1}} ×⋯×C^{u_{n}} → C^{v_{1}}, …, F_{m}: C^{u_{1}} ×⋯×C^{u_{n}} → C^{v_{m}}, ⟨F_{1}, …, F_{m}⟩ is a functor of C^{u_{1}} × ⋯ × C^{u_{n}} → C^{v_{1}} × ⋯ × C^{v_{m}}.

[figure: C^{u_{1}} × ⋯ × C^{u_{n}}; F_{1}; ⋮; F_{i}; ⋮; F_{m}; C^{v_{1}}; ⋮; C^{v_{i}}; ⋮; C^{v_{m}}; ⇒; C^{u_{1}} × ⋯ × C^{u_{n}}; ⟨F_{1}, …, F_{m}⟩; C^{v_{1}} × ⋯ × C^{v_{m}}]

Proof: It is trivial from the definition of products in Cat. []

The two propositions allow us to combine functors only if the source and target categories match exactly. For example, F: C → C and G: C^{−} → C cannot be composed into G ∘ F. Therefore, we have to first convert functors of C^{v_{1}} × ⋯ × C^{v_{n}} → C into those of C^{v′_{1}} × ⋯ × C^{v′_{n}} → C^{u}. There are two ways to do so.

Firstly, from definition 2.1.9, functor F of varity v_{1} … v_{n}, that is F is a functor of C^{v_{1}} × ⋯ × C^{v_{n}} → C, into

F^{u}: (C^{v_{1}} × ⋯ × C^{v_{n}})^{u} → C^{u} ≅ C^{v_{1}•u} × ⋯ × C^{v_{n}•u} → C^{u}

The isomorphism is from proposition 2.1.5 and proposition 2.1.4.

The other way of conversion is using embedding functors and coercing functors into greater variances (e.g. covariant functor can be a fixed variant functor).

Definition 2.1.13: If u_{1} ⊑ v_{1}, …, u_{n} ⊑ v_{n} and F is a functor of varity u_{1} … u_{n}, we can coerce it to a functor of varity v_{1} … v_{n} by

F |_{u_{1}...u_{n}}^{v_{1}...v_{n}} =^{def} F ∘ (e_{u_{1},v_{1}} × ⋯ × e_{u_{n},v_{n}}).

[figure: C^{v_{1}} × ⋯ × C^{v_{n}}; e_{u_{1},v_{1}} × ⋯ × e_{u_{n},v_{n}}; C^{u_{1}} × ⋯ × C^{u_{n}}; F; C]

We may write F |^{v_{1}...v_{n}} when u_{1} … u_{n} is obvious. []

Let us now define the composition of mixed variant functors.

Definition 2.1.14: Let F be a functor of varity u_{1} … u_{n} and G_{1}, …, G_{n} be functors of varity v_{11} … v_{1m}, …, v_{n1} … v_{nm}, respectively. Then we have a functor F [G_{1}, …, G_{n}] CHAPTER 2. CATEGORICAL SPECIFICATION LANGUAGE 23 of varity w_{1} … w_{m} where w_{i} =^{def} u_{1} • v_{1i} ⊔ ⋯ ⊔ u_{n} • v_{ni}^{1}. The definition of the functor is

F [G_{1}, …, G_{n}] =^{def} F ∘ ⟨G_{1}^{u_{1}}|^{w_{1}...w_{m}}, …, G_{n}^{u_{n}}|^{w_{1}...w_{m}}⟩

Proof of well-definedness: G_{i} is a functor of C^{v_{i1}} × ⋯ × C^{v_{im}} → C. G_{i}^{u_{i}} is a functor of C^{u_{i}•v_{i1}} × ⋯ × C^{u_{i}•v_{im}} → C^{u_{i}}. Since u_{i} • v_{i1} ⊑ w_{1}, …, u_{i} • v_{im} ⊑ w_{m}, from definition 2.1.13 G_{i}^{u_{i}}|^{w_{1}...w_{m}} is a functor of C^{w_{1}} × ⋯ × C^{w_{m}} → C^{u_{i}}. From proposition 2.1.12 ⟨G^{u_{1}}|^{w_{1}...w_{m}}, …, G^{u_{n}}|^{w_{1}...w_{m}}⟩ is a functor of C^{w_{1}} ×⋯×C^{w_{m}} → C^{u_{1}} ×⋯×C^{u_{n}}. Therefore, from proposition 2.1.11,

F ∘ ⟨G^{u_{1}}|^{w_{1}...w_{m}}, …, G^{u_{n}}|^{w_{1}...w_{m}}⟩: C^{w_{1}} × ⋯ × C^{w_{m}} → C

is a functor of varity w_{1} … w_{m}. [] The variances of G_{1}, …, G_{n} are appropriately modified according to the varity of F and then the least upper bound is taken so that we can pair them together. We need some lemmas to show the associativity of the composition. Lemma 2.1.15: Let u ⊑ v and F be a functor of varity w_{1} … w_{n}.

1. For any w, u • w ⊑ v • w and (e_{u,v})^{w} = e_{u•w,v•w}.

2. The following diagram commutes.

[figure: C^{v•w_{1}} × ⋯ × C^{v•w_{n}}; e_{u,v}^{w_{1}} × ⋯ × e_{u,v}^{w_{n}}; C^{u•w_{1}} × ⋯ × C^{u•w_{n}}; F^{v}; F^{u}; C^{v}; e_{u,v}; C^{v}]

In other words, the action of Var on functors is natural with respect to the partial order ⊑.

3. e_{u,v} ∘ F^{v} = F^{u}|^{w_{1}•v...w_{n}•v}

4. F |^{u_{1}...u_{n}}|^{v_{1}...v_{n}} = F |^{u_{1}⊔v_{1}...u_{n}⊔v_{n}}

5. (F ∘ G)^{u} = F^{u} ∘ G^{u}

6. ⟨F_{1}, …, F_{n}⟩^{u} = ⟨F_{1}^{u}, …, F_{n}^{u}⟩

7. (F |^{v_{1}...v_{n}})^{u} = F^{u}|^{v_{1}•u...v_{n}•u}

(w_{1}, …, w_{m}) = (u_{1}, …, u_{n}) (\begin{matrix}v_{11} & … & v_{1m} \\ ⋮ & ... & ⋮ \\ v_{n1} & … & v_{nm} \end{matrix} )

1Var is a commutative semiring with unit: ⊔ as its addition and • as its multiplication. If we express varities as vectors, then varity of F [G_{1}, …, G_{n}] can be computed by the following matrix multiplication.

CHAPTER 2. CATEGORICAL SPECIFICATION LANGUAGE 24

Proof: We have to check any pairs of u and v 1 and 2 hold from the definitions. 3 follows 2. 4, 5 and 6 are easy to show and 7 follows them.

(F |^{v_{1}...v_{n}})^{u} = (F ∘ (e_{w_{1},v_{1}} × ⋯ × e_{w_{n},v_{n}}))^{u} = F^{u} ∘ (e_{w_{1},v_{1}} × ⋯ × e_{w_{n},v_{n}})^{u} = F^{u} ∘ ((e_{w_{1},v_{1}})^{u} × ⋯ × (e_{w_{n},v_{n}})^{u}) = F^{u} ∘ (e_{w_{1}•u,v_{1}•u} × ⋯ × e_{w_{n}•u,v_{n}•u}) = F^{u}|^{v_{1}•u...v_{n}•u} []

Proposition 2.1.16: Let F, G_{1}, …, G_{n} and H_{1}, …, H_{m} be functors of the following varities:

F: u_{1} … u_{n}
G_{1}: v_{11} … v_{1m}, …, G_{n}: v_{n1} … v_{nm}
H_{1}: w_{11} … w_{1l}, …, H_{n}: w_{m1} … w_{ml}

Then, the following equality between functors holds:

(F [G_{1}, …, G_{n}])[H_{1}, …, H_{m}] = F [G_{1}[H_{1}, …, H_{m}], …, G_{n}[H_{1}, …, H_{m}]].

Proof: Let varity a_{1} … a_{m}, b_{11} … b_{1l}, …, b_{n1} … b_{nl} and c_{1} … c_{l} be

(a_{1}, …, a_{m}) =^{def} (u_{1}, …, u_{n}) (\begin{matrix}v_{11} & … & v_{1m} \\ ⋮ & ... & ⋮ \\ v_{n1} & … & v_{nm} \end{matrix} ) ,

(\begin{matrix}b_{11} & … & b_{1l} \\ ⋮ & ... & ⋮ \\ b_{n1} & … & b_{nl} \end{matrix} ) =^{def} (\begin{matrix}v_{11} & … & v_{1m} \\ ⋮ & ... & ⋮ \\ v_{n1} & … & v_{nm} \end{matrix} ) (\begin{matrix}w_{11} & … & w_{1l} \\ ⋮ & ... & ⋮ \\ w_{m1} & … & w_{ml} \end{matrix} ) , and

(c_{1}, …, c_{l}) =^{def} (u_{1}, …, u_{n}) (\begin{matrix}v_{11} & … & v_{1m} \\ ⋮ & ... & ⋮ \\ v_{n1} & … & v_{nm} \end{matrix} ) (\begin{matrix}w_{11} & … & w_{1l} \\ ⋮ & ... & ⋮ \\ w_{m1} & … & w_{ml} \end{matrix} ) .

Then,

(F [G_{1}, …, G_{n}])[H_{1}, …, H_{m}] = F ∘ ⟨G_{1}^{u_{1}}|^{a_{1}...a_{m}}, …, G_{n}^{u_{n}}|^{a_{1}...a_{m}}⟩ ∘ ⟨H_{1}^{a_{1}}|^{c_{1}...c_{l}}, …, H_{m}^{a_{m}}|^{c_{1}...c_{l}}⟩ = F ∘ ⟨G_{1}^{u_{1}}|^{a_{1}...a_{m}} ∘ ⟨H_{1}^{a_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩ = F ∘ ⟨G_{1}^{u_{1}} ∘ (e_{v_{11}•u_{1},a_{1}} × ⋯ × e_{v_{1m}•u_{1},a_{m}}) ∘ ⟨H_{1}^{a_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩ = F ∘ ⟨G_{1}^{u_{1}} ∘ ⟨e_{v_{11}•u_{1},a_{1}} ∘ H_{1}^{a_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩ = F ∘ ⟨G_{1}^{u_{1}} ∘ ⟨H^{v_{1}1•u_{1}}|^{w_{11}•v_{1}•u_{1}...w_{1l}•v_{1}•u_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩ = F ∘ ⟨G_{1}^{u_{1}} ∘ ⟨H^{v_{1}1•u_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩

whereas

F [G_{1}[H_{1}, …, H_{m}], …, G_{n}[H_{1}, …, H_{m}]] = F ∘ ⟨(G_{1} ∘ ⟨H_{1}^{v_{11}}|^{b_{11}...b_{1l}}, …, H_{m}^{v_{1m}}|^{b_{11}...b_{1l}}⟩)^{u_{1}}|^{c_{1}...c_{l}}, …⟩ = F ∘ ⟨G_{1}^{u_{1}} ∘ ⟨H_{1}^{v_{11}•u_{1}}|^{b_{11}•u_{1}...b_{1l}•u_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩ = F ∘ ⟨G_{1}^{u_{1}} ∘ ⟨H_{1}^{v_{11}•u_{1}}|^{c_{1}...c_{l}}, …⟩, …⟩

Therefore, the proposition holds. [] Mixed variant functors form an algebraic theory but with an extra structure. Mixed variant functors are functions between four sorts, +, −, ⊥ and ⊤.

Finally, we can show what functorial expressions like H(G(X, Y), F (X)) mean. Let Γ be a Var^{∗}-indexed set of primitive functor names^{2}. Then, we define

FE(Γ) =^{def} the set of terms constructed from Γ and variables like term al- gebras.

CFE(Γ) =^{def} { λ(X_{1}, …, X_{n}).E | E ∈ FE(Γ) and X_{1}, …, X_{n} includes all the variables in E }

We call elements of FE(Γ) functorial expressions over Γ and call elements of CFE(Γ) closed functorial expressions over Γ. As we can convert any lambda closed term in a term algebra to a morphism in the corresponding algebraic theory, we can convert any closed functorial expression into functors. Let ξ be an assignment of functor symbols in Γ_{v_{1}...v_{n}} to real functors of varity v_{1} … v_{n} in C, that is, ξ is a Var^{∗}-indexed function such that

ξ_{v_{1}...v_{n}}: Γ_{v_{1}...v_{n}} → Funct(C^{v_{1}} × ⋯ × C^{v_{n}}, C)

where Funct(D, E) is the category of functors from D to E. We may write ξF for ξ_{v_{1}...v_{n}}(F). We can extend assignment ξ to that over CFE(Γ) as follows

ξ(λ(X_{1}, …, X_{n}).E) =^{def} ξ_{X_{1},...,X_{n}}(E)

where ξ_{X_{1},...,X_{n}} assigns expressions in FE(Γ) which have X_{1}, …, X_{n} as variables to functors of n variables and is defined by

ξ_{X_{1},...,X_{n}}(X_{i}) =^{def} Π_{i}^{n}: C^{⊥} × ⋯ C^{+} × ⋯ C^{⊥} → C

ξ_{X_{1},...,X_{n}}(F (E_{1}, …, E_{n})) =^{def} ξF [ξ_{X_{1},...,X_{n}}(E_{1}), …, ξ_{X_{1},...,X_{n}}(E_{n})]

where Π_{i}^{n} is the ith projection of the n fold product of C.

Example 2.1.17: Let Γ consist of a unary functor symbol F which is covariant, a functor symbol G of varity ++ and a functor symbol H of varity −+. Let ξ be an assignment of Γ. Then, λ(X, Y).H(G(X, Y), F (X)) denotes the following functor by ξ.

ξ(λ(X, Y).H(G(X, Y), F (X))) = ξH[ξG[Π_{1}^{2}, Π_{2}^{2}], ξF [Π_{1}^{2}]]

The varity of Π_{1}^{2} is +⊥, that of ξF is + and, therefore, from definition 2.1.14, ξF [Π_{1}^{2}] has varity +⊥. The varity of Π_{1}^{2} is +⊥, that of Π_{2}^{2} is ⊥+, that of ξG is ++ and from definition 2.1.14 the varity of ξG[Π_{1}^{2}, Π_{2}^{2}] is

(+, +) (\begin{matrix}+ & ⊥ \\ ⊥ & + \end{matrix}) = (+ • + ⊔ + • ⊥, + • ⊥ ⊔ + • +) = (+ ⊔ ⊥, ⊥ ⊔ +) = (+, +)

Finally, the varity of the whole functor is

(−, +) (\begin{matrix}+ & + \\ + & ⊥ \end{matrix}) = (− • + ⊔ + • +, − • + ⊔ + • ⊥) = (− ⊔ +, − ⊔ ⊥) = (⊤, −),

so it is fixed-variant in X and contravariant in Y. [] The last proposition in this section is to establish the relationship between the syntactic substitution of functorial expressions and the composition of functors defined in definition 2.1.14.

2From now on, we distinguish names (or symbols) from what they denote.

Proposition 2.1.18: Let

λ(X_{1}, …, X_{n}).E and λ(Y_{1}, …, Y_{m}).E_{1}, …, λ(Y_{1}, …, Y_{m}).E_{n}

be closed functorial expressions. Then,

ξ(λ(X_{1}, …, X_{n}).E)[ξ(λ(Y_{1}, …, Y_{m}).E_{1}), …, ξ(λ(Y_{1}, …, Y_{m}).E_{n})]
= ξ(λ(Y_{1}, …, Y_{m}).E[E_{1}/X_{1}, …, E_{n}/X_{n}])

where E[E_{1}/X_{1}, …, E_{n}/X_{n}] is E in which X_{1}, …, X_{n} are replaced by E_{1}, …, E_{n}, respectively. Proof: We can easily prove it by structural induction on E using proposition 2.1.16 []

From this correspondence, for closed functorial expression K of n variables and L_{1}, …, L_{n} of m variables, we write

K[L_{1}, …, L_{n}]

for a closed functorial expression of m variables which is obtained by replacing n variables in K by L_{1}, …, L_{n}. Then, the proposition is

ξ(K[L_{1}, …, L_{n}]) = ξK[ξL_{1}, …, ξL_{n}].

2.2 Signatures of Categorical Specification Language

A specification normally consists of a signature, which says what kind of sorts there are and what kinds of operations there are, and a set of sentences (or equations), which give properties of the operations. A specification defines a class of models which have what the signature says and satisfies the sentences. Therefore, in order to define a specification language, we have to define what its signatures are, what its sentences are and what its models are. However, it is often convenient to define, first, models without being constrained by sentences and, then, define a satisfaction relation between a statement and a model determining whether the statement is true in the model or not. A model which satisfies all the sentences is called a theory model. See institutions [Goguen and Burstall 83] for a categorical abstract definition of what specification languages are.

A CSL signature will be divided into three parts; in the first part, we will declare some names for functors, which will serve as parameterized data types (or data type constructors); in the second part, we will declare some names for natural transformations, which will serve as polymorphic functions over the parameterized data types; and in the third part, we will declare some names for factorizers (or mediating morphisms), which will be necessary to put initial or final constrains on the data types.

The first part can be presented as a Var^{∗}-indexed set Γ. F in Γ_{v_{1}...v_{n}} is said to have varity v_{1} … v_{n}. We may write F (v_{1}, …, v_{n}) to indicate this.

Γ looks almost like an equational signature for algebraic specification languages. It is as if Var were the set of sorts and Γ were a set of operations over the sorts. The only difference is that Γ is not a Var^{∗}×Var-indexed set but simply a Var^{∗}-indexed set. This is because we can apply Var to functors to get other functors as we explained in definition 2.1.9, so it is sufficient to give Γ as a Var^{∗}-indexed set.

Note that Γ is one sorted. Each signature describes only one category. However, because we are dealing with one level higher objects, it has the power to describe more than one data type (or sort) inside one signature. We will illustrate this later in this section.

In the second part, a CSL signature introduces some symbols for natural transformations. Normally, a natural transformation is defined as follows: given two functors F, G: C → D, a natural transformation α: F →^{·} G is a function which assigns to each A ∈ |C| a morphism α_{A}: F (A) → G(A) such that for any morphism f: A → B in C the following diagram commutes.

[figure: F (A); α_{A}; G(A); F (f); G(f); F (B); α_{B}; G(B)]

As we have seen in section 2.1, closed functorial expressions provide more complicated functors constructed from primitive functors in Γ. Let Λ be CFE(Γ). We index the set of natural transformations by two closed functorial expressions, that is, the second part of a CSL signature is given by a Λ×Λ-indexed set Δ; α ∈ Δ_{K,L} will denote a natural transformation ξK →^{·} ξL, where ξK and ξL will be the denotations of K and L, respectively. We may write α: K →^{·} L to indicate this. Since a natural transformation should go between functors of the same number of variables, Δ_{K,L} should be empty when K and L have different number of variables. Even if they have the same number of variables, their variances may be different. In that case, we take the least upper bound of two variances.

The third and the final part of a CSL signature introduces symbols for factorizers (or mediating morphisms). In general, a factorizer is an isomorphism associated with an adjunction. If F ⟼ G where F: C → D and G: D → C, the factorizer ψ gives the following natural isomorphism between hom sets.

ψ: Hom_{D}(F (A), B) ⟶^{≅} Hom_{C}(A, G(B))

For example, the factorizer associated with the binary product functor ‘prod’ (: C×C → C) is ‘pair’ which gives for any two morphisms f: C → A and g: C → B a morphism pair(f, g): C → prod(A, B). We can write this situation as the following rule.

\frac{C ⟶^{f} A C ⟶^{g} B}{C ⟶^{pair(f,g)} prod(A, B)}

In CSL, factorizers are given by a (Λ×Λ)^{∗}×(Λ×Λ)-indexed set Ψ (Λ = CFE(Γ)). The index (Λ×Λ)^{∗} specifies the type of morphisms to which a factorizer can be applied and the index Λ×Λ specifies the type of morphisms obtained by applying the factorizer. For

ψ ∈ Ψ_{⟨K_{1},L_{1}⟩...⟨K_{m},L_{m}⟩,⟨K,L⟩},

we may write it as the following rule.

\frac{f_{1}: K_{1} → L_{1} … f_{m}: K_{m} → L_{m}}{ψ(f_{1}, …, f_{m}): K → L}

where f_{1}, …, f_{n} are auxiliary names of morphisms introduced for this rule. As we have restricted the indexed set Δ, Ψ should be indexed by functors of the same number of variables, and also we take the least upper bound of the variances and regard it as the overall variance.

Hence, we come to the definition of CSL signatures.

Definition 2.2.1: A CSL signature is a triple ⟨Γ, Δ, Ψ⟩, where Γ is a Var^{∗}-indexed set, Δ is a Λ×Λ-indexed set (where Λ = CFE(Γ)) for natural transformations and Ψ is a (Λ×Λ)^{∗}×(Λ×Λ)-indexed set for factorizers. As a restriction to the triple, Δ_{K,L} should be empty if K and L has the different number of variables and Ψ_{⟨⟨K_{1},L_{1}⟩...⟨K_{m},L_{m}⟩,⟨K,L⟩⟩} should also be empty if K_{i}, L_{i}, K and L do not have the same number of variables. []

As an example, we will give a CSL signature for cartesian closed categories.

Example 2.2.2: A cartesian closed category can be characterized as a category having three special functors: terminal object ‘1’ (which is a constant functor), binary product ‘prod’ and exponential ‘exp’. Therefore,

Γ_{()} = {1},  Γ_{++} = {prod},  Γ_{−+} = {exp},

where ‘()’ denotes the empty string in Var^{∗}. The rest of Γ_{s} are empty. We sometimes write the index set Γ as

{1, prod(+, +), exp(−, +)}.

The product functor ‘prod’ is associated with two natural transformations which give projection morphisms.

π_{1}: λ(X, Y).prod(X, Y) →^{·} λ(X, Y).X

π_{2}: λ(X, Y).prod(X, Y) →^{·} λ(X, Y).Y

If there is no ambiguity, we may write them by listing their components as follows:

π_{1}_{A,B}: prod(A, B) → A
π_{2}_{A,B}: prod(A, B) → B

Functors (Γ) 1 prod(+, +) exp(−, +)
Natural Transformations (Δ) π_{1}: prod(A, B) → A

π_{2}: prod(A, B) → B

ev: prod(exp(A, B), A) → B

Factorizers (Ψ)  \overline{!: A → 1}

\frac{f: C → A g: C → B}{pair(f, g): C → prod(A, B)}

\frac{h: prod(C, A) → B}{curry(h): C → exp(A, B)}

Figure 2.1: CSL Signature for Cartesian Closed Categories

We might even omit subscripts from π_{1}_{A,B} and π_{2}_{A,B}. The exponential functor ‘exp’ is associated with one natural transformation which gives evaluation morphisms.

ev: λ(X, Y).prod(exp(X, Y), X) →^{·} λ(X, Y).Y

Note that the variance of these two functors is ⊤+. Therefore, Δ is

Δ_{λ(X,Y).prod(X,Y),λ(X,Y).X}  = {π_{1}}
Δ_{λ(X,Y).prod(X,Y),λ(X,Y).Y}  = {π_{2}}
Δ_{λ(X,Y).prod(exp(X,Y),X),λ(X,Y).Y} = {ev}

For any other combinations of closed functorial expression K and L, Δ_{K,L} is empty.

Finally, there are three factorizers for the three functors: ‘!’ for ‘1’, ‘pair’ for ‘prod’ and ‘curry’ for ‘exp’.

\overline{!: λ(X).X → λ(X).1}
f: λ(X, Y, Z).Z → λ(X, Y, Z).X g: λ(X, Y, Z).Z → λ(X, Y, Z).Y

pair(f, g): λ(X, Y, Z).Z → λ(X, Y, Z).prod(X, Y)

\frac{h: λ(X, Y, Z).prod(Z, X) → λ(X, Y, Z).Y}{curry(h): λ(X, Y, Z).Z → λ(X, Y, Z).exp(X, Y)}

If there is no ambiguity, we might write these rules down as in figure 2.1, where we summarize the definition of the CSL signature for cartesian closed categories. We will omit the tedious formal definition of Ψ as an indexed set. []

As we mentioned earlier, a CSL signature is one sorted, but because it handles higher objects, it is no less powerful than a many sorted equational signature. Let us demonstrate this. An equational signature is given by a pair ⟨S, Σ⟩ where S is a set (of sort names) and Σ is an S^{∗}×S-indexed set (of operator names). We will translate it to a corresponding CSL signature ⟨Γ, Δ, Ψ⟩. Since functors play a role of sorts, we declare a constant functor for each sort in S.

Γ_{()} = S,

and we have a binary product functor to deal with sequences of sorts,^{3} and the terminal object for constants.

Γ_{++} = { prod } and Γ_{()} = { 1 }

Operations will be translated to natural transformations: for each operation o ∈ Σ_{s_{1}...s_{n},s}, we have a natural transformation of the same name.

o: prod(s_{1}, prod(…, prod(s_{n−1}, s_{n}))) → s

that is,

Δ_{λ().prod(s_{1},prod(...,prod(s_{n−1},s_{n}))),λ().s} = Σ_{s_{1}...s_{n},s}

We also have two projections for ‘prod’ in Δ and Ψ has only one factorizer ‘pair’ for pairing. It is easy to see that the CSL signature ⟨Γ, Δ, Ψ⟩ corresponds to the equational signature ⟨S, Σ⟩.

Proposition 2.2.3: A many-sorted equational signature can be represented by a CSL signature. []

It is interesting to know that we represented a many-sorted equational signature by a category with products because an algebraic theory can exactly be given as a category with products [Lawvere 63].

Let us make CSL signatures form a category by extending a pre-CSL signature morphism in a natural way. Intuitively, a signature morphism (not only in CSL but in general) does some renamings of symbols and/or some mergings of symbols.

Definition 2.2.4: A CSL signature morphism σ from a CSL signature ⟨Γ, Δ, Ψ⟩ to a CSL signature ⟨Γ′, Δ′, Ψ′⟩ is a triple ⟨σ′, σ′′, σ′′′⟩ consisting of

1. a Var^{∗}-indexed function σ′_{v_{1}...v_{n}}: Γ_{v_{1}...v_{n}} → Γ′_{v_{1}...v_{n}} for mapping functor names,

2. a Λ×Λ-indexed function (where Λ = CFE(Γ)) σ′′_{K,L}: Δ_{K,L} → Δ′_{σ′K,σ′L} for mapping natural transformation names, and

3. a (Λ×Λ)^{∗}×(Λ×Λ)-indexed function

σ′′′_{⟨⟨K_{1},L_{1}⟩...⟨K_{m},L_{m}⟩,⟨K,L⟩⟩}: Ψ_{⟨⟨K_{1},L_{1}⟩...⟨K_{m},L_{m}⟩,⟨K,L⟩⟩} → Ψ′_{⟨⟨σ′K_{1},σ′L_{1}⟩...⟨σ′K_{m},σ′L_{m}⟩,⟨σ′K,σ′L⟩⟩}

for mapping factorizer names.

We often write σF for σ′_{v_{1}...v_{n}}(F), σα for σ′′_{K,L}(α) and σψ for σ′′′_{⟨⟨K_{1},L_{1}⟩...,⟨K,L⟩⟩}(ψ). []

Definition 2.2.5: The category of CSL signatures CSig has CSL signatures as its objects and CSL signature morphisms as its morphisms. The identity morphism on a CSL signature ⟨Γ, Δ, Ψ⟩ consists of the corresponding identity functions for the components and the composition of CSL morphisms is given by combining the component-wise compositions as indexed functions. This clearly forms a category. []

3We could have n-ary product functors for all natural numbers as well, but since we can represent them using a binary one, we only declare the binary one.

2.3 Structures of Categorical Specification Language

In this section, we will define CSL structures. A CSL signature specifies symbols for functors, natural transformations and factorizers, so intuitively, a CSL structure is a category associated with these functors, natural transformations and factorizers.

Definition 2.3.1: Given a CSL signature ⟨Γ, Δ, Ψ⟩, a CSL structure ⟨C, ξ⟩ is a small category C together with an assignment ξ

1. ξ assigns each functor name of varity v_{1} … v_{n} to a functor C^{v_{1}} × ⋯ × C^{v_{n}} → C.^{4} As we have seen in section 2.1, ξ can be extended to the assignment of closed functorial expressions to functors.

2. ξ assigns each natural transformation name α ∈ Δ_{K,L}, where K and L are closed functorial expressions of n variables, to a set of C morphisms

ξα_{A_{1},...,A_{n}}: ξK(A_{1}, …, A_{n}) → ξL(A_{1}, …, A_{n})

for arbitrary C objects A_{1}, …, A_{n}.^{5}

3. Each factorizer symbol ψ ∈ Ψ_{⟨⟨K_{1},L_{1}⟩...,⟨K,L⟩⟩}, where K_{1}, L_{1},…, K_{m}, L_{m}, K, L are closed functorial expressions of n variables, is assigned to a set of Set functions

ξψ_{A_{1},...,A_{n}}: ∏_{i=1}^{m} Hom_{C}(ξK_{i}(A_{1}, …, A_{n}), ξL_{i}(A_{1}, …, A_{n}))

→ Hom_{C}(ξK(A_{1}, …, A_{n}), ξL(A_{1}, …, A_{n}))
for arbitrary C objects A_{1}, …, A_{n}. []

Note that we do not assign a natural transformation symbol to a natural transformation, but it is mapped to a set of morphisms and whether they form a natural transformation or not is left to be stated by equations.

Example 2.3.2: Let ⟨Γ, Δ, Ψ⟩ be the CSL signature for cartesian closed categories defined in example 2.2.2. Then, any cartesian closed category is a CSL structure of this signature by obvious assignment of the symbols to the functors, natural transformations and factorizers. However, the converse is not true. We can have a category which has three functors, three natural-transformation-look-alikes and three factorizerlook-alikes. CSL structures do not require mapping natural transformation symbols to natural transformations but only to a set of morphisms, nor do they require mapping factorizer symbols to factorizers. The factorizer-look-alikes may not give unique morphisms or may not commute some diagrams. []

4We could say ξ is a Var^{∗}-indexed function

ξ_{v_{1}...v_{n}}: Γ_{v_{1}...v_{n}} → Funct(C^{v_{1}} × ⋯ × C^{v_{n}}, C).

5We could express it as a Λ×Λ-indexed function (where Λ = CFE(Γ))

ξ_{K,L}: Δ_{K,L} → Nat(ξK|^{⊤...⊤}, ξL|^{⊤...⊤}).

CSL structure morphisms are defined simply as a kind of homomorphisms. They keep the structure nicely.

Definition 2.3.3: Given a CSL signature ⟨Γ, Δ, Ψ⟩, a CSL structure morphism from a CSL structure ⟨C, ξ⟩ to another ⟨D, ζ⟩ is a covariant functor T: C → D such that

1. for any F in Γ_{v_{1}...v_{n}}

T ∘ ξF = ζF ∘ (T^{v_{1}} × ⋯ × T^{v_{n}})

holds,

[figure: C^{v_{1}} × ⋯ × C^{v_{n}}; T^{v_{1}} × ⋯ × T^{v_{n}}; D^{v_{1}} × ⋯ × D^{v_{n}}; ξF; ζF; C; D]

2. for any α ∈ Δ_{K,L} and for any C objects A_{1}, …, A_{n}

T (ξα_{A_{1},...,A_{n}}) = ζα_{T (A_{1}),...,T (A_{n})},

and

3. for any ψ ∈ Ψ_{⟨K_{1},L_{1}⟩...⟨K_{m},L_{m}⟩,⟨K,L⟩}, for any C objects A_{1}, …, A_{n} and for any C morphisms f_{i}: ξK_{i}(A_{1}, …, A_{n}) → ξL_{i}(A_{1}, …, A_{n}) (i = 1, …, m),

T (ξψ_{A_{1},...,A_{n}}(f_{1}, …, f_{m})) = ζψ_{T (A_{1}),...,T (A_{n})}(T (f_{1}), …, T (f_{m})). []

Hence, the category of CSL structures is:

Definition 2.3.4: For a CSL signature ⟨Γ, Δ, Ψ⟩, the category of CSL structures, CMod(⟨Γ, Δ, Ψ⟩), has CSL structures as objects and CSL structure morphisms as morphisms; the identity morphism on ⟨C, ξ⟩ is the identity functor I_{C} and the composition of morphisms is the composition of their underlying functors. []

2.4 Functorial Calculus (revisit)

In section 2.1 we saw functorial expressions denote functors. In this section we will see an expression involving natural transformation symbols and factorizer symbols denote a set of morphisms.^{6} For example, under the signature of cartesian closed categories given in example 2.2.2, what should the following expression denote?

π_{1} ∘ prod(curry(π_{2}), I)

We even have a problem for expressions like π_{1}∘π_{2} because π_{1} and π_{2} are not projections of the same product: π_{2} is of prod(A, prod(B, C)) and π_{1} is of prod(B, C). Actually, natural transformations are polymorphic like ML functions are.^{7} As we defined in definition 2.3.1, π_{1} denotes a set of morphisms.

ξπ_{1}_{A,B}: ξprod(A, B) → A

We have to figure out for each occurrence of π_{1} what A and B are.

Definition 2.4.1: For a CSL signature ⟨Γ, Δ, Ψ⟩, we have a set Exp(Γ, Δ, Ψ) of CSL expressions defined by the following BNF.

e : : = I | e_{1} ∘ e_{2} | α | ψ(e_{1}, …, e_{m}) | F (e_{1}, …, e_{n}) | f

where α ∈ Δ, ψ ∈ Ψ and f is a variable for morphisms. We also have a set AExp(Γ, Δ, Ψ) of CSL annotated expressions defined by the following BNF.

e : : = \begin{matrix}I[K] | e_{1} ∘ e_{2} | α[K_{1}, …, K_{n}] | ψ[K_{1}, …, K_{n}](e_{1}, …, e_{m}) | \\ F (e_{1}, …, e_{n}) | f \end{matrix}

where K_{1}, …, K_{n} are closed functorial expressions over Γ. []

It is trivial to see that for each annotated expression there is a corresponding expression (i.e. forgetting all the annotations, […]), which we call skeleton of the annotated expression. We are going to type-check an expression first and, then, we determine its denotation. Annotated expressions are used to remember the type-checking information inside expressions. We will give the typing rules for annotated expressions and show that every expression has the most general annotated expression and we take the type of this annotated expression as the type of the expression.

First, we define the notion of unification.

Definition 2.4.2: A closed functorial expression K of n variables is said to be more general than a closed functorial expression K′ of m variables if there are closed functorial expressions K_{1}, …, K_{n} of m variables such that

K[K_{1}, …, K_{n}] ≡ K′

6Some may want it to denote a natural transformation, but the treatment of factorizers seems very complicated to do so.

7Conversely, ML polymorphic functions are natural transformations. The author has not yet seen the definite statement of this, but it is a folklore among computer scientists dealing with category theory.

This fact is rarely used in practice, but it sometimes helps to understand the behaviour of polymorphic functions. For example, any ML function f of type αlist → int should never depend on elements in the list but only to the length of list. As another example, if f is of type αlist → αlist and if we apply it to an integer list [1, 4, 3, 5] and get [5, 1, 3], we know the result of applying f to [2, 8, 6, 10] (each element is doubled) without actually applying it. The result should be [10, 2, 6], i.e. each element of the result is doubled as well.

where ≡ is the equivalence relation ignoring variable renaming. (Trivially, K ≡ K′ implies ξK = ξK′.) []

Definition 2.4.3: Closed functorial expressions K and L are said to be unifiable when there is a closed functorial expression K′ such that K′ is less general than K as well as L. []

Proposition 2.4.4: If closed functorial expressions K and L are unifiable, then there is a most general unification, that is, there exist K_{1}, …, K_{n} and L_{1}, …, L_{m} such that K[K_{1}, …, K_{n}] ≡ L[L_{1}, …, L_{m}] and for any K′ which is less general than K and K′ there are K′_{1}, …, K′_{l} such that K′ ≡ K[K_{1}, …, K_{n}][K′_{1}, …, K′_{l}]. Proof: Same as ordinary unification of terms. []

Let us now define the type of annotated expressions.

Definition 2.4.5: Let ⟨Γ, Δ, Ψ⟩ be a CSL signature. An annotated expression e has a type ρ ⊢ e: K → L when it can be derived from the following rules, where ρ is a given assignment of each morphism variable to its type and K and L are closed functorial expressions.

1. For the identity, ρ ⊢ I[K]: K → K.

2. For the composition,

\frac{ρ ⊢ e_{1}: K′ → L ρ ⊢ e_{2}: K → K′}{ρ ⊢ e_{1} ∘ e_{2}: K → L} .

3. For a natural transformation α ∈ Δ_{K,L}, where K and L are of n variables,

ρ ⊢ α[K_{1}, …, K_{n}]: K[K_{1}, …, K_{n}] → L[K_{1}, …, K_{n}]

4. For a factorizer ψ ∈ Ψ_{⟨⟨K_{1},L_{1}⟩...⟨K_{m},L_{m}⟩,⟨K,L⟩⟩}, where K_{i}, L_{i}, K, L are of n variables,

\frac{ρ ⊢ e_{i}: K_{i}[K′_{1}, …, K′_{n}] → L_{i}[K′_{1}, …, K′_{n}]}{ρ ⊢ ψ[K′_{1}, …, K′_{n}](e_{1}, …, e_{m}): K[K′_{1}, …, K′_{n}] → L[K′_{1}, …, K′_{n}]}

5. For a functor F ∈ Γ_{v_{1}...v_{n}}

\frac{ρ ⊢ e_{i}: K_{i}⟶^{v_{i}}L_{i}}{ρ ⊢ F (e_{1}, …, e_{n}): F [K_{1}, …, K_{n}] → F [L_{1}, …, L_{n}]}

where e_{i}: K_{i}⟶^{v_{i}}L_{i} is e_{i}: K_{i} → L_{i} if v_{i} is + or ⊥, e_{i}: L_{i} → K_{i} if v_{i} is − and

I: K_{i} → K_{i} if v_{i} is ⊤.

6. For a morphism variable f, ρ ⊢ f: ρ(f). [] Definition 2.4.6: We say an annotated expression e is more general than e′ if there exist closed functorial expressions K_{1}, …, K_{n} such that e′ ≡ e[K_{1}, …, K_{n}], where e[K_{1}, …, K_{n}] is e with all its annotations being composed with K_{1}, …, K_{n}, e.g. α[L_{1}, …, L_{m}][K_{1}, …, K_{n}] is α[L_{1}[K_{1}, …, K_{n}], …, L_{m}[K_{1}, …, K_{n}]]. []

Proposition 2.4.7: If an annotated expression e has a type ρ ⊢ e: K → L, e[K_{1}, …, K_{n}] has the following type.

ρ[K_{1}, …, K_{n}] ⊢ e[K_{1}, …, K_{n}]: K[K_{1}, …, K_{n}] → L[K_{1}, …, K_{n}]

where ρ[K_{1}, …, K_{n}](f) is K′[K_{1}, …, K_{n}] → L′[K_{1}, …, K_{n}] when ρ(f) is K′ → L′. Proof: It can easily proved from definition 2.4.5 by structural induction on e. []

Proposition 2.4.8: Let e ∈ Exp(Γ, Δ, Ψ) be an expression of a CSL signature ⟨Γ, Δ, Ψ⟩. If there exists an annotated expression e′ whose skeleton is e and if it has a type, then there exists a most general annotated expression which has a type and whose skeleton is e. Proof: It can be proved by structural induction on e. Here, we present an algorithm of calculating a most general annotated expression.

1. If e is I, the most general annotated expression is I[I], where I is the identity closed functorial expression λ(X).X.

2. If e is e_{1} ∘ e_{2}, from induction hypothesis, we have the most general annotated expressions for e_{1} and e_{2}.

ρ_{1} ⊢ e′_{1}: K → K′ ρ_{2} ⊢ e′_{2}: L → L′

We unify K with L′ achieving K[K_{1}, …, K_{n}] ≡ L′[L_{1}, …, L_{m}]. The most general annotated expression for e and its type is

ρ ⊢ e′_{1}[K_{1}, …, K_{n}] ∘ e′_{2}[L_{1}, …, L_{m}]: L[L_{1}, …, L_{m}] → K′[K_{1}, …, K_{n}]

where ρ is the result of combining ρ_{1}[K_{1}, …, K_{n}] and ρ_{2}[L_{1}, …, L_{m}].

3. If e is a natural transformation α ∈ Δ_{K,L}, the most general annotated expression

and its type is

ρ ⊢ α[Π_{1}^{n}, …, Π_{n}^{n}]: K → L,

where Π_{i}^{n} is the closed functorial expression λ(X_{1}, …, X_{n}).X_{i}.

4. If e is ψ(e_{1}, …, e_{m}) for a factorizer ψ ∈ Ψ_{⟨⟨K_{1},L_{1}⟩...,⟨K,L⟩⟩}, from induction hypothesis, we have annotated expressions e′_{i} such that

ρ_{i} ⊢ e′_{i}: K′_{i} → L′_{i}.

We unify K′_{i} with K_{i} and L′_{i} with L_{i}. If the unification is successful, we have the most general annotated expression for e.

ρ ⊢ ψ[J_{1}, …, J_{n}](e′_{1}[J′_{11}, …], …, e′_{m}[J′_{1m}, …]):
K[J_{1}, …, J_{n}] → L[J_{1}, …, J_{n}]

where J_{1}, …, J_{n}, J′_{11}, … are the substitution for K_{i} and L_{i} obtained from the unification and ρ is the result of combining ρ_{i}[J′_{1i}, …].

5. If e is F (e_{1}, …, e_{n}), let the most general annotated expressions for e_{i} be

ρ_{i} ⊢ e′_{i}: K_{i}⟶^{v_{i}}L_{i}.

Then, the most general annotated expression for e and its type is

ρ ⊢ F (e′_{1}, …, e′_{n}): F [K_{1}, …, K_{n}] → F [L_{1}, …, L_{n}].

6. If e is a morphism variable f, its most general annotated expression is itself and has the following type.

ρ ⊢ f: λ(X, Y).X → λ(X, Y).Y []

From this proposition,

Definition 2.4.9: We define the type of an expression e ∈ Exp(Γ, Δ, Ψ) to be the type of the most general annotated expression e′ whose skeleton is e. []

Let us finally define the denotation of expressions in Exp(Γ, Δ, Ψ) when a CSL structure ⟨C, ξ⟩ is given. Since each expression e is associated uniquely to the most general annotated expression e′ by proposition 2.4.8, we can define the denotation of e to be that of e′ and define the denotation of annotated expressions.

Definition 2.4.10: Let ⟨Γ, Δ, Ψ⟩ be a CSL signature and ⟨C, ξ⟩ be a CSL structure. For an annotated expression e ∈ AExp(Γ, Δ, Ψ) of type ρ ⊢ e: K → L (where K and L are of l variables), we define its denotation, ξe, to be a set of morphisms

(ξe)_{A_{1},...,A_{l}}: ξK(A_{1}, …, A_{l}) → ξL(A_{1}, …, A_{n})

for any C objects A_{1}, …, A_{l} and for any morphism variable assignment ω (where ω(f, A_{1}, …, A_{l}) gives a morphism of type ξK′(A_{1}, …, A_{l}) → ξL′(A_{1}, …, A_{l}) when ρ(f) is K′ → L′).

1. For the identity,

(ξI[K])_{A_{1},...,A_{l}} =^{def} I_{ξK[A_{1},...,A_{l}]}

2. For compositions,

(ξe_{1} ∘ e_{2})_{A_{1},...,A_{l}} =^{def} (ξe_{1})_{A_{1},...,A_{l}} ∘ (ξe_{2})_{A_{1},...,A_{l}}

3. For natural transformations,

(ξα[K_{1}, …, K_{n}])_{A_{1},...,A_{l}} =^{def} ξα_{ξK_{1}(A_{1},...,A_{l}),...,ξK_{n}(A_{1},...,A_{l})}

4. For factorizers,

(ξψ[K_{1}, …, K_{n}](e_{1}, …, e_{m}))_{A_{1},...,A_{l}} =^{def}

ψ_{ξK_{1}(A_{1},...,A_{l}),...,ξK_{n}(A_{1},...,A_{l})}((ξe_{1})_{A_{1},...,A_{l}}, …, (ξe_{m})_{A_{1},...,A_{l}})

5. For functors,

(ξF (e_{1}, …, e_{n}))_{A_{1},...,A_{l}} =^{def} ξF ((ξe_{1})_{A_{1},...,A_{l}}, …, (ξe_{n})_{A_{1},...,A_{l}})

6. For morphism variables,

(ξf)_{A_{1},...,A_{n}} =^{def} ω(f, A_{1}, …, A_{l})

Proof of well-definedness: We have to show, for example, for a natural transformation α ∈ Δ_{K,L}, (ξα[K_{1}, …, K_{n}])_{A_{1},...,A_{l}} is a morphism from

ξK[K_{1}, …, K_{n}](A_{1}, …, A_{l}) to ξL[K_{1}, …, K_{n}](A_{1}, …, A_{l}).

This holds because from definition 2.3.1 ξα_{ξK_{1}(A_{1},...,A_{l}),...,ξK_{n}(A_{1},...,A_{l})} is a morphism from ξK(ξK_{1}(A_{1}, …, A_{l}), …)) to ξL(ξK_{1}(A_{1}, …, A_{l}), …) and from proposition 2.1.18 it is from ξK[K_{1}, …, K_{n}](A_{1}, …, A_{l}) to ξL[K_{1}, …, K_{n}](A_{1}, …, A_{l}). []

Example 2.4.11: Let ⟨Γ, Δ, Ψ⟩ be a CSL signature for cartesian closed categories presented in example 2.2.2 and ⟨C, ξ⟩ be a CSL structure of this signature where C is a cartesian closed category and ξ is the standard assignment (i.e. the product symbol to the product functor and so on). Let us find out the denotation of ev ∘ pair(f, π_{2}). First, we have to find out the corresponding most general annotated expression and its type by the algorithm used to prove proposition 2.4.8.

1. ev ∘ pair(f, π_{2}) is given by composing ev and pair(f, π_{2}), so we need to calculate the most general annotated expressions for these two sub-expressions first.

(a) ev is a natural transformation, and its most general annotated expression is

ρ_{1} ⊢ ev[Π_{1}^{2}, Π_{2}^{2}]: prod[exp, Π_{1}^{2}] → Π_{2}^{2}.

(b) pair(f, π_{2}) is given by applying the factorizer pair to f and π_{2}.

i. ‘f’ is a morphism variable, its most general annotated expression is

ρ_{2} ⊢ f: Π_{1}^{2} → Π_{2}^{2}.

ii. π_{2} is a natural transformation, and its most general annotated expres-

sion is

ρ_{3} ⊢ π_{2}[Π_{1}^{2}, Π_{1}^{2}]: prod → Π_{2}^{2}.

CHAPTER 2. CATEGORICAL SPECIFICATION LANGUAGE 38

pair has the type

⟨⟨Π_{3}^{3}, Π_{1}^{3}⟩⟨Π_{3}^{3}, Π_{2}^{3}⟩, ⟨Π_{3}^{3}, prod[Π_{1}^{3}, Π_{2}^{3}]⟩⟩

By unification, we get the most general annotated expression for pair(f, π_{2}).

ρ_{4} ⊢ pair[Π_{3}^{3}, Π_{2}^{3}, prod[Π_{1}^{3}, Π_{2}^{3}]](f, π_{2}[Π_{1}^{3}, Π_{2}^{3}]):

prod[Π_{1}^{3}, Π_{2}^{3}] → prod[Π_{3}^{3}, Π_{2}^{3}]

where ρ_{4} maps f to prod[Π_{1}^{3}, Π_{2}^{3}] → Π_{3}^{3}. Unifying prod[Π_{3}^{3}, Π_{2}^{3}] and prod[exp, Π_{1}^{2}], we get the most general annotated expression for ev ∘ pair(f, π_{2}).

ρ_{5} ⊢ ev[Π_{2}^{3}, Π_{3}^{3}] ∘ pair[exp[Π_{2}^{3}, Π_{3}^{3}], Π_{2}^{3}, prod[Π_{1}^{3}, Π_{2}^{3}]](f, π_{2}[Π_{1}^{3}, Π_{2}^{3}])

: prod[Π_{1}^{3}, Π_{2}^{3}] → Π_{3}^{3}

where ρ_{5} maps f to prod[Π_{1}^{3}, Π_{2}^{3}] → exp[Π_{2}^{3}, Π_{3}^{3}]. From definition 2.4.10, the denotation of this annotated expression is a set of morphisms for objects A, B and C and a morphism variable assignment

ω(f, A, B, C): ξprod(A, B) → ξexp(B, C).

1. (ξev[Π_{2}^{3}, Π_{3}^{3}])_{A,B,C} = ξev_{B,C}

2. (ξf)_{A,B,C} = ω(f, A, B, C)

3. (ξπ_{2}[Π_{1}^{3}, Π_{2}^{3}])_{A,B,C} = ξπ_{2}_{A,B}

4. (ξpair[…](f, π_{2}[…]))_{A,B,C} = ξpair_{ξexp(B,C),B,ξprod(A,B)}(ω(f, A, B, C), ξπ_{2}_{A,B})

5. (ξev[…] ∘ pair[…](f, π_{2}[…]))_{A,B,C} =

ξev_{B,C} ∘ ξpair_{ξexp(B,C),B,ξprod(A,B)}(ω(f, A, B, C), ξπ_{2}_{A,B})

Therefore, the denotation of ev ∘ pair(f, π_{2}) is ξev_{B,C} ∘ ξpair_{ξexp(B,C),B,ξprod(A,B)}(ω(f, A, B, C), ξπ_{2}_{A,B}) []

2.5 Sentences and Satisfaction Relation of Categorical Specification Language

In this section, we will finish defining the specification language CSL at last. First, we define what a CSL sentence is.

Definition 2.5.1: A CSL conditional equation is a sequence of CSL expression pairs and a CSL expression pair. We usually write it as

e_{1} = e′_{1} ∧ … ∧ e_{n} = e′_{n} ⇒ e = e′,

or simply e = e′ if the preceding sequence is empty. To be typed, it needs to share the same morphism variable environment, e_{i} and e′_{i} have to have the same type and e and e′ have to have the same type. We may write the types as follows:

ρ ⊢ e_{1} = e′_{1}: K_{1} → L_{1} ∧ … ∧ e_{n} = e′_{n}: K_{n} → L_{n} ⇒ e = e′: K → L

We write CEq(Γ, Δ, Ψ) for the set of all the CSL conditional equations which can be typed. []

The CSL conditional equations are the CSL sentences. We now have to define the satisfaction relation for CSL. We have separately defined what CSL structures are and what CSL conditional equations are. The satisfaction relation connects these two together so that we can say a CSL conditional equation holds or not in a particular CSL structure.

Definition 2.5.2: Let ⟨Γ, Δ, Ψ⟩ be a CSL signature. A CSL structure ⟨C, ξ⟩ satisfies a CSL conditional equation

e_{1} = e′_{1} ∧ … ∧ e_{n} = e′_{n} ⇒ e = e′

having a type

ρ ⊢ e_{1} = e′_{1}: K_{1} → L_{1} ∧ … ∧ e_{n} = e′_{n}: K_{n} → L_{n} ⇒ e = e′: K → L,

if and only if for any objects A_{1}, …, A_{l} and any morphism variable assignment ω we have either

1. a CSL equation e_{i} = e′_{i} such that (ξe_{i})_{A_{1},...,A_{l}} ≠ (ξe′_{i})_{A_{1},...,A_{l}}, or

2. (ξe)_{A_{1},...,A_{l}} = (ξe′)_{A_{1},...,A_{l}}.

We will write

⟨C, ξ⟩ ⊧ e_{1} = e′_{1} ∧ … ∧ e_{n} = e′_{n} ⇒ e = e′

when ⟨C, ξ⟩ satisfies this CSL conditional equation. []

We have defined the specification language, CSL: CSL signatures, CSL structures, CSL conditional equations and CSL satisfaction relation. We could have defined it as an institution (see [Goguen and Burstall 83]) by defining CMod as a contravariant functor and showing CSL satisfaction condition.

Finally, let us finish presenting the CSL theory (i.e. a pair of CSL signature and CSL conditional equations) of cartesian closed categories.

Example 2.5.3: We have presented the signature for cartesian closed categories in example 2.2.2 (or figure 2.1), so all we have to do is to list the CSL conditional equations. (Note that they are not conditional for this example.)

1.f = !

2.1 = I

3.pair(π_{1}, π_{2}) = I

4.π_{1} ∘ pair(f, g) = f

5.π_{2} ∘ pair(f, g) = g

6.pair(f, g) ∘ h = pair(f ∘ h, g ∘ h)

7.prod(f, g) = pair(f ∘ π_{1}, g ∘ π_{2})

8.curry(ev) = I

9.ev ∘ curry(prod(f, I)) = f 10.curry(f) ∘ g = curry(f ∘ prod(g, I)) 11.exp(f, g) = curry(g ∘ eval ∘ prod(f, I))

The naturality of π_{1}, π_{2} and ev can be derived from these equations. For example, the naturality of π_{1} is shown by

π_{1} ∘ prod(f, g) = π_{1} ∘ pair(f ∘ π_{1}, g ∘ π_{2}) = f ∘ π_{1}. []

2.6 Free Categories

One of the major advantages of algebraic specification methods using equations or conditional equations over other specification methods is that any theory has an initial model (i.e. the initial object in the category of models which satisfy the theory). This also holds for CSL, and in this section, we will construct an initial structure for a CSL theory. Remember that a CSL structure is a pair of a category and an interpretation. The category of an initial CSL structure corresponds to a so-called free category.

Given a CSL signature ⟨Γ, Δ, Ψ⟩ and a set Θ of CSL conditional equations, we are going to define a special category C and an interpretation ξ. For simplicity, we assume that Γ does not contain any free-variant functors. (We can always get such a signature by discarding free-variant arguments. This does not affect its semantics at all.)

Definition 2.6.1: We say that a closed functorial expression is ground if it has no variables, that is, its basic form is λ().E. We take ground closed functorial expressions as the objects of C. []

The definition of morphisms of C is a little bit more complicated, so we define them step by step.

Definition 2.6.2: A ground annotated expression is an annotated expression such that 1. all the annotation, [K_{1}, …, K_{n}] consists of ground closed functorial expressions,

and

2. it does not contain any morphism variables. []

Proposition 2.6.3: If a ground annotated expression e has a type ρ ⊢ e: K → L, and both K and L are ground functorial expressions. Proof: We can easily prove it from definition 2.4.5 by structural induction. []

The following will give us the basis of the morphisms in C.

Definition 2.6.4: For ground closed functorial expressions K and L, we define

GExp(K, L) =^{def} { e | e is ground and ∅ ⊢ e: K → L } []

To make GExp proper morphisms, we introduce a family of equivalence relations ≡ indexed by a pair of ground functorial expressions. Each ≡_{K,L} is an equivalence relation on GExp(K, L).

Definition 2.6.5: We define ≡ to be the smallest relation satisfying the following conditions. (In the following, to simplify the presentation, we omit indexes of ≡ if there is no ambiguity.)

1. ≡ is an equivalence relation, that is, reflexive, symmetric and transitive.

2. If e_{1} ≡_{K,L} e′_{1} and e_{2} ≡_{K′,K} e′_{2}, then e_{1} ∘ e_{2} ≡_{K′,L} e′_{1} ∘ e′_{2}.

3. If e ∈ GExp(K, L), then I[L] ∘ e ≡ e and e ∘ I[K] ≡ e.

4. For a functor symbol F ∈ Γ_{v_{1}...v_{n}}, if e_{1} ≡ e′_{1}, … and e_{n} ≡ e′_{n}, then F (e_{1}, …, e_{n}) ≡ F (e′_{1}, …, e′_{n}).

5. For a factorizer symbol ψ ∈ Ψ_{⟨⟨K′_{1},L′_{1}⟩...⟨K′_{l},L′_{l}⟩,⟨K′,L′⟩⟩} and ground functorial expressions K_{1}, …, K_{n}, if e_{1} ≡ e′_{1}, … and e_{l} ≡ e′_{l}, then

ψ[K_{1}, …, K_{n}](e_{1}, …, e_{l}) ≡ ψ[K_{1}, …, K_{n}](e′_{1}, …, e′_{l}).

6. Finally, for a conditional CSL equation e_{1} = e′_{1} ∧ … ∧ e_{n} = e′_{n} ⇒ e = e′ ∈ Θ whose type is

ρ ⊢ e_{1} = e′_{1}: K′_{1} → L′_{1} ∧ … ∧ e_{n} = e′_{n}: K′_{n} → L′_{n} ⇒ e = e′: K′ → L′

with ρ(f_{i}) is K′′_{i} → L′′_{i}, ground functorial expressions K_{1}, …, K_{m}, and ground annotated expressions

e′′_{i} ∈ GExp(K′′_{i}[K_{1}, …, K_{m}], L′′_{i}[K_{1}, …, K_{m}]),

if for all j = 1, …, n

(e_{j}[K_{1}, …, K_{m}])[e′′_{1}, …, e′′_{l}/f_{1}, …, f_{l}] ≡
(e′_{j}[K_{1}, …, K_{m}])[e′′_{1}, …, e′′_{l}/f_{1}, …, f_{l}],

then

(e[K_{1}, …, K_{m}])[e′′_{1}, …, e′′_{l}/f_{1}, …, f_{l}] ≡
(e′[K_{1}, …, K_{m}])[e′′_{1}, …, e′′_{l}/f_{1}, …, f_{l}]. []

We can now define the morphisms of C.

Definition 2.6.1 (continued): The C morphisms from K to L are the equivalence classes of GExp(K, L) by ≡_{K,L}, or simply,

Hom_{C}(K, L) =^{def} GExp(K, L)/≡_{K,L}.

We write ⟨e⟩ for the equivalence class to which e belongs. []

Proposition 2.6.6: C is a category. Proof: The identity morphism of a C object K is given by ⟨I[K]⟩. The composition of ⟨e⟩: K → L and ⟨e′⟩: K′ → K is defined by

⟨e⟩ ∘ ⟨e′⟩ =^{def} ⟨e ∘ e′⟩.

The composition is trivially associative, and the satisfiability of the absorption rules of the identities is guaranteed by the third condition of the equivalence relation ≡ defined in definition 2.6.5. []

Let us define an interpretation ξ so that ⟨C, ξ⟩ is a CSL structure of the CSL signature ⟨Γ, Δ, Ψ⟩.

Definition 2.6.7: The definition of ξ is divided into three.

1. For a functor symbol F ∈ Γ_{v_{1}...v_{n}}, ξF is a functor C^{v_{1}...v_{n}} → C defined by

ξF (K_{1}, …, K_{n}) =^{def} F [K_{1}, …, K_{n})], and

ξF (⟨e_{1}⟩, …, ⟨e_{n}⟩) =^{def} ⟨F (e_{1}, …, e_{n})⟩.

2. For a natural transformation symbol α ∈ Δ_{K,L}, ξα is

ξα_{K_{1},...,K_{n}} =^{def} ⟨α[K_{1}, …, K_{n}]⟩.

3. Finally, for a factorizer symbol ψ ∈ Ψ_{⟨⟨K_{1},L_{1}⟩...⟨K_{n},L_{n}⟩,⟨K,L⟩⟩}, ξψ is

ξψ_{K′_{1},...,K′_{n}}(⟨e_{1}⟩, …, ⟨e_{n}⟩) =^{def} ⟨ψ[K′_{1}, …, K′_{n}](e_{1}, …, e_{n})⟩. []

Proposition 2.6.8: ⟨C, ξ⟩ is a CSL structure of ⟨Γ, Δ, Ψ⟩. Moreover, it is a theory structure of the CSL theory given by the set Θ of CSL conditional equations. Proof: The condition 6 in definition 2.6.5 makes it satisfy the conditional equations. [] We have constructed a special CSL structure ⟨C, ξ⟩, and we will next show that it is the initial object in the full-subcategory of CMod(⟨Γ, Δ, Ψ⟩) of all the structures satisfying Θ.

Theorem 2.6.9: For any CSL structure satisfying Θ, there is a unique CSL structure morphism from ⟨C, ξ⟩. Proof: Let ⟨D, ζ⟩ be an arbitrary CSL structure satisfying Θ. Using the denotation of annotated expressions on this structure (see definition 2.4.10), we define a functor T from C to D as follows:

T (K) =^{def} ζK and T (⟨e⟩) =^{def} ζe.

Note that, since K is a ground functorial expression ζK is an D object, and that, since e is a ground annotated expression, ζe is a D morphism (it does not need objects A_{1}, …, A_{m} or a morphism variable assignment ω). It is easy to see that T is a (covariant) functor (note that we have to show the well-definedness first). It is also not so difficult to show that T is a CSL structure morphism and that it is the unique one from ⟨C, ξ⟩ to ⟨D, ζ⟩ (simply extending the result on algebraic specifications). []

The advantage of working in an initial CSL structure is that, if we show that a conditional equation holds in the initial one, then we automatically know that it holds in any CSL structure. In chapter 4, we will define the symbolic computation in categories and it can be regarded as the computation in free categories.

Categorical Data Types

In chapter 2, we introduced categorical data types from a point of view of a specification language defining categories. Although the specification language CSL is a rigorous language, it is rather tedious and categoritians may never define categories in that way. In this chapter, we will give another presentation of categorical data types, which will be simpler and more intuitive. This is also the way Categorical Data Types originated. Note that we are not discarding CSL completely and that the semantics of categorical data types will be given in terms of CSL.

Section 3.1 is an extended introduction to categorical data types. We will investigate some conventional data types and introduce a new uniform categorical way of defining data types. In section 3.2, we will make this new way into the CDT declaration mechanism. Section 3.3 will give various examples of CDT declarations. In section 3.4, CDT declarations will be connected to CSL theories, and finally in section 3.5 we will give a construction of CDT data types.

3.1 What are Categorical Data Types?

The need for pairs of two (or more) items of data often arises when we write programs. It is often the case that a function or procedure takes more than one argument and this means that a pair (or a record) of data needs to be passed to the function or procedure. In another situation, we may want to declare a new data type whose element is a pair of elements of other data types. In PASCAL, we can define such data types using its record … end construct. For example, intchar whose element is a pair of an integer and a character can be declared as:

     type intchar = record
                       first: integer;
                       second: char
                   end;

In ML, this can be done by

     type intchar = int * string;

(where since ML does not have a type for representing characters, we have to use ‘string’ type whose element is a sequence of characters). These two languages have the means of constructing data types of pairs from already-existing data types. Let us call the constructors product type constructors. Most of the current programming languages have product type constructors in one way or another as their built-in primitives because they are so essential that we can even say that no programming language is complete without them.

In order to understand the nature of product type constructors, let us suppose a programming language which does not have them as primitives and that we have to define them in terms of others. This might mean that we need in the language some kind of one level higher operations which can define not types but type constructors. Let us refer to an algebraic specification language CLEAR,^{1} and see its ability to define a product type constructor.

     constant Triv =
         theory
            sort element
         endth
     procedure Prod(A:Triv,B:Triv) =
         theory
            data sort prod
            opns pair: element of A,element of B -> prod
                 pi1 : prod -> element of A
                 pi2 : prod -> element of B
            eqns all a:element of A,b:element of B,
                                       pi1(pair(a,b)) = a
                 all a:element of A,b:element of B,
                                       pi2(pair(a,b)) = b
         endth

This defines an algebra P of three sorts: two ‘element’ sorts (let us call them ‘A-element’ and ‘B-element’ to distinguish them) and a ‘prod’ sort. The underlying set |P |_{prod} is the (set) product of two sets |P |_{A−element} and |P |_{B−element}. The declaration also defines three operations (or functions), ‘pair’, ‘pi1’ and ‘pi2’, satisfying the two equations listed. Note that the following equation can be proved using induction on ‘prod’ sort (we have the induction principle on this sort because of the initial data constraint).

                 all x: prod, pair(pi1(x),pi2(x)) = x

An algebraic specification language like CLEAR is powerful enough to allow us to define all kinds of type constructors (including ordinary data types as constant type constructors) in a uniform way without having any particular primitives. However, because of its use of equations, we cannot adopt its declaration mechanism in ordinary programming languages.^{2} We might be puzzled that we need equations even to define such very basic data types as products.

1CLEAR can be institution independent, but here we refer the one that uses the equational algebraic institution.

Let us find whether there is any other ways of defining product type constructors by examining the foundation, namely mathematics. Modern mathematics uses set theory extensively because of its power. Set theory does not have a product type constructor as its primitive construct either, so it is defined by means of other constructs. For sets A and B, their (set) product is defined as:

A × B =^{def} { (x, y) | x ∈ A, y ∈ B }

where (x, y) is really an abbreviation of {{x} {x y}}. Although this looks very simple, it actually needs some work to show from the axioms of set theory that this is actually a set. Set theory uses the power of first order logic so heavily that it is much harder to put the set theory formalism into a programming language than to put the algebraic specification formalism. As an example, let ϕ(x) be a first order formula. Then, from the comprehension axiom (or the replacement axiom), we have the set

{ x ∈ A | ϕ(x) }

where A is a set. ϕ(x) can be anything expressible by first order logic (using quantifiers and negations), and this is too much powerful to investigate the basic property of data types. It disfigures the beauty behind this powerful definition mechanism and we cannot see through it easily.

Set theory has achieved a firm position as the foundation of mathematics, but there are some alternatives. Category theory is one of them. It has been proved that category theory has a remarkable ability to disclose true nature of mathematical objects. For example, a product constructor (or categorically a functor C × C → C) is beautifully characterized as the right adjoint of the diagonal functor C → C × C.^{3} Expanding the definition of adjunctions, this means that we have the following natural isomorphism:

Hom_{C}(C, A) × Hom_{C}(C, B) ≃ Hom_{C}(C, prod(A, B))  (∗)

(natural in A, B and C). We use ‘prod’ for the product functor to follow the notation we use later. The isomorphic function from the left-hand side to the right-hand side is the factorizer of this adjunction and we write ‘pair’ for it. We can rewrite this adjoint situation as the following rule:

\frac{C ⟶^{f} A C ⟶^{g} B}{C ⟶^{pair(f,g)} prod(A, B)}  (∗∗)

Given two morphisms f: C → A and g: C → B, pair(f, g) give a morphism of C → prod(A, B). This correspondence is one-to-one and is natural in A, B and C.

2There is a programming language OBJ [Goguen and Tardo 79] which treats equations as a kind of programs (as rewrite rules).

3There may be more than one right adjoint of the diagonal functor, but they are isomorphic. Therefore, we say ‘the’ right adjoint rather than ‘a’ right adjoint.

Comparing with the product type constructor ‘Prod’ defined by CLEAR, we have the same ‘pair’ though the previous one takes two elements as the arguments and this one takes two morphisms instead, and now we can find the things corresponding to two projections ‘pi1’ and ‘pi2’ as well. Replacing C by prod(A, B) in (∗), we get:

Hom_{C}(prod(A, B), A) × Hom_{C}(prod(A, B), B) ≃
Hom_{C}(prod(A, B), prod(A, B)).

We have a very special morphism in Hom_{C}(prod(A, B), prod(A, B)), namely the identity. Because of the isomorphism, there exist unique morphisms of prod(A, B) → A and prod(A, B) → B which are mapped to the identity by ‘pair’, and these are the projections. We name them ‘pi1’ and ‘pi2’ as well. Because of the very way they are defined, it is trivial that

pair(pi1, pi2) = I.  (+)

Furthermore, from the naturality in C of (∗), we have the rule

\frac{C ⟶^{pair(f,g)} prod(A, B) ⟶^{pi1} A C ⟶^{pair(f,g)} prod(A, B) ⟶^{pi2} B}{C ⟶^{pair(f,g)} prod(A, B) ⟶^{pair(pi1,pi2)} prod(A, B)} ,

and, if we express it by equations and use (+),

pair(pi1 ∘ pair(f, g), pi2 ∘ pair(f, g)) = pair(pi1, pi2) ∘ pair(f, g) = pair(f, g).

Since ‘pair’ is isomorphic, we can conclude that the following equations hold:

pi1 ∘ pair(f, g) = f and pi2 ∘ pair(f, g) = g.

These are exactly the ones which we listed when defining ‘Prod’ in CLEAR. Note that this time they are derived equations. By saying that ‘prod’ is the right adjoint to the diagonal functor, we get these equations automatically. This shows how neat the categorical definition is.

Another advantage of categorical definition is that we can form the dual definition easily. We defined the product functor as the right adjoint of the diagonal functor. Then, it is natural to ask what is the left adjoint of the diagonal functor. It is the coproduct functor C × C → C. In the category of sets, the copoduct of two sets A and B is their disjoint sum

A + B =^{def} { 0 } × A ⋃{ 1 } × B.

It is not easy to see in set theory that this is the dual of A × B. In PASCAL, we can define coproducts by means of variant record. In ML, we used to have a built-in coproduct type constructor ‘+’, but the new Standard ML does not. Instead, ‘+’ can be defined by the following ‘datatype’ declaration.

               datatype 'a + 'b = in1 of 'a | in2 of 'b;

We cannot define the product type constructor by a ‘datatype’ declaration in ML, but we can define its dual. ML looks non-symmetric from this. In CLEAR, we can define a coproduct type constructor as follows:

     Procedure CoProd(A:Triv,B:Triv) =
         theory
            data sort coprod
            opns in1: element of A -> coprod
                 in2: element of B -> coprod
         endth

Again, this cannot be seen as the dual of ‘Prod’ we defined earlier; here we do not use equations; we have only two operations whereas we had three. This shows that CLEAR is not symmetric either.

Now, in category theory, the coproduct functor C × C → C which we call ‘coprod’ is defined by the dual of (∗), by just changing the direction of arrows.

Hom_{C}(A, C) × Hom_{C}(B, C) ≃ Hom_{C}(coprod(A, B), C)

We name the isomorphic function going from the left-hand side to the right-hand side ‘case’ (we could call it ‘copair’ to emphasize the duality to ‘pair’, but, since it plays a role of ‘case’ statements of ML or C (or PASCAL), we call it ‘case’). Writing the adjunction as a rule,

\frac{A ⟶^{f} C B ⟶^{g} C}{coprod(A, B) ⟶^{case(f,g)} C} .

Two injections in1: A → coprod(A, B) and in2: B → coprod(A, B) are defined as the morphisms which ‘case’ maps to the identity of coprod(A, B). As before, we can derive some equations easily.

From what we have looked at, it seems a good idea to design a category theory based (programming or specification) language which has the ability to define functors by means of adjunctions. Since it is convenient to introduce names for unit natural transformations and factorizers at the same time, we regard an adjunction as a triple of a functor, a unit natural transformation and a factorizer (see, for example, [Mac Lane 71] for many equivalent ways of defining adjunctions). Therefore, a category theory based language may have the following two forms of declaring new functors:

let ⟨F, α, ψ⟩ be right adjoint of G let ⟨F, α, ψ⟩ be left adjoint of G

where G is a functor we already have, F is the new functor we are defining, α is the associated unit natural transformation and ψ is the associated factorizer. One problem is that we need to have some primitive functors with which we start. We definitely need diagonal functors for we want to define product and coproduct functors. In order to define the natural number object (which is a constant functor), we need a pretty complicated functor G. The problem is how to represent such G.

Let us investigate how other languages and theories define the data type of natural numbers. In set theory, it has the axiom of infinity which says the existence of natural numbers. This may look rather artificial. In PASCAL, there is no intuitively easy way to define it. In ML, though it is a built-in data type for efficiency, we could define it as:

                  datatype nat = zero | succ of nat;

Note the recursiveness in this definition. Essentially, we need some kind of recursiveness to define a data type of natural numbers. In CLEAR, one can define it as

     constant Nat =
       theory
         data sort nat
         opns zero: nat
             succ: nat -> nat
       endth

This is very much similar to the one in ML, though we often think that the CLEAR definition is based on the initial algebra semantics whereas the ML definition is based on domain theory. In domain theory, a data type of natural numbers can be defined as the solution of the following domain equation

N ≅ 1 + N.  (∗)

The initial solution of (∗) can be calculated as a colimit of a sequence of domains, but we do not go into its detail here. As a connection to the initial algebra semantics, the initial solution can be characterized as the initial T -algebra, where T is a functor T (X) =^{def} 1 + X in this case. In general, given a category and an endo-functor T, we can form a category of T -algebras.

Definition 3.1.1: For a category C and an endo-functor T: C → C, the category of T -algebras is defined

1. its objects are pairs ⟨A, f⟩ where A is a C object and f is a C morphism T (A) → A, and

2. its morphisms h: ⟨A, f⟩ → ⟨B, g⟩ are C morphisms h: A → B which make the following diagram commute.

[figure: T (A); f; A; T (h); h; T (B); g; B]

Note that this is a weaker version of the category of T -algebras defined in many category theory books (e.g. [Mac Lane 71]) where T needs to be a monad. [] We can dualize definition 3.1.1 to define T -coalgebras. However, in the theory of categorical data types (‘CDT theory’ for short), we combine the two definitions together.

Definition 3.1.2: Let C and D be categories and both F and G be functors from C to D. We define an F, G-dialgebra^{4} as

1. its objects are pairs ⟨A, f⟩ where A is a C object and f is a D morphism of F (A) → G(A), and

2. its morphisms h: ⟨A, f⟩ → ⟨B, g⟩ are C morphisms h: A → B such that the following diagram commutes.

[figure: F (A); f; G(A); F (h); G(h); F (B); g; G(B)]

In the case where F or G is contravariant, we have to modify the direction of some arrows.

It is easy to show that it is a category; let us write DAlg(F, G) for it. Note that DAlg(T, I) is the category of T -algebras and DAlg(I, T) is the category of T -coalgebras. []

This is a very simple extension of definition 3.1.1, yet its symmetry and dividing the source category from the target one give us greater freedom. With T -algebras, we need to use the coproduct functor to define the domain of natural numbers, but by F, G-dialgebra we do not. Let C be any category and D be its product C × C. We define the functors F and G as

F (A) =^{def} ⟨1, A⟩ and G(A) =^{def} ⟨A, A⟩.

Let ⟨nat, ⟨zero, succ⟩⟩ be the initial F, G-dialgebra. From the definition, ‘nat’ is a C object, ‘zero’ is a C morphism of 1 → nat and ‘succ’ is a C morphism of nat → nat. The initiality means that for any DAlg(F, G) object ⟨A, ⟨f, g⟩⟩ there exists a unique DAlg(F, G) morphism h: ⟨nat, ⟨zero, succ⟩⟩ → ⟨A, ⟨f, g⟩⟩. If we spell out the definition, this means that for any C object A and any C morphisms f: 1 → A and g: A → A there exists a unique C morphism h: nat → A which makes the following diagram commute.

[figure: 1; zero; nat; succ; nat; f; h; h; A; A; g] 4The name dialgebra was suggested by Bob McKay.

This is exactly the definition of ‘nat’ being a natural number object in category theory.

To get further generality of F, G-dialgebras, we parametrize F and G.

Definition 3.1.3: Let C, D and E be categories, and let F: C×D → E and G: C×D^{−} → E be functors. We define ⟨Left[F, G](A), η_{A}⟩ for a D object A to be the initial object in the category DAlg(F ( · , A), G( · , A)). Dually, we define ⟨Right[F, G](A), ϵ_{A}⟩ to be the final object. We may write Right(A) for Right[F, G](A) and Left(A) for Left[F, G](A) if the context makes F and G clear. []

Proposition 3.1.4: If Left[F, G](A) exists for every object A ∈ |D|, Left[F, G] denotes a functor D → C (i.e. we can extend it to D morphisms). Dually, if Right[F, G](A) exists for every A ∈ |D|, Right[F, G] denotes a functor D^{−} → C. Proof: We first need to define what Left[F, G](f) is for a D morphism f: A → B. We define it as the morphism h: Left(A) → Left(B) which fills in the following diagram.

[figure: F (Left(A), A); η_{A}; G(Left(A), A); ⟨Left(A), η_{A}⟩; F (h, I); G(h, I); h; F (Left(B), A); G(Left(B), A); ⟨Left(B), G(I, f) ∘ η_{B} ∘ F (I, f)⟩; F (I, f); G(I, f); F (Left(B), B); η_{B}; G(Left(B), B)]

The unique existence of the morphism is provided because ⟨Left(A), η_{A}⟩ is the initial object of DAlg(F ( · , A), G( · , A)). In other words, Left(f) is the unique morphism which satisfies

G(Left(f), f) ∘ η_{B} ∘ F (Left(f), f) = η_{A}.

Let us check that Left is in fact a functor. Trivially,

G(I, I) ∘ η_{A} ∘ F (I, I) = η_{A}.

Therefore, Left(I_{A}) = I_{Left(A)}. For morphisms f: A → B and g: B → C,

G(Left(g) ∘ Left(f), g ∘ f) ∘ η_{C} ∘ F (Left(g) ∘ Left(f), g ∘ f)
= G(Left(f), f) ∘ G(Left(g), g) ∘ η_{C} ∘ F (Left(g), g) ∘ F (Left(f), f)
= G(Left(f), f) ∘ η_{B} ∘ F (Left(f), f)
= η_{A}

Therefore, Left(g) ∘ Left(f) = Left(g ∘ f).

[figure: F (Left(A), A); G(Left(A), A); F (Left(B), B); G(Left(B), B); F (Left(C), C); G(Left(C), C); η_{A}; η_{B}; η_{C}; F (Left(f), f); G(Left(f), f); F (Left(g), g); G(Left(g), g); F (Left(g ∘ f), g ∘ f); G(Left(g ∘ f), g ∘ f)]

Dually, we can prove that Right is a functor. []

‘Left’ and ‘Right’ may suggest a connection with left and right adjoint functors. In fact,

Proposition 3.1.5: For a functor F: C → D, its left adjoint functor can be denoted by

Left[λ(X, Y).Y, λ(X, Y).F (X)]

and, dually, its right adjoint functor can be denoted by

Right[λ(X, Y).F (X), λ(X, Y).Y].

Proof: Let us only check the left adjoint case. We see λ(X, Y).Y as a functor C ×D → D and λ(X, Y).F (X) as a functor C ×D^{−} → D. From definition 3.1.3, Left is a functor D → C. If we spell out the condition of ⟨Left(A), η_{A}⟩ being the initial algebra, it means that for any C object B and a C morphism f: A → F (B) there exists a unique C morphism h: Left(A) → B such that the following diagram commutes.

[figure: A; η_{A}; F (Left(A)); Left(A); A; F (B); B; f; F (h); h]

This is exactly the condition of Left being the left adjoint functor of F. Dually, we can prove that Right[λ(X, Y).F (X), λ(X, Y).Y] is the right adjoint. []

Hence, definition 3.1.2 of F, G-dialgebras covers both T -algebras and adjoints so that it enables us to define products, coproducts, natural number object, and so on in a uniform way.

3.2 Data Type Declarations in Categorical Data Types

In the previous section, we have looked at some ways of defining data types in some languages. In this section, we will introduce how to define data types in CDT.

If we were only interested in functors, only Left[F, G] and Right[F, G] defined in the previous section would be needed, but we do want morphisms (or natural transformations) and factorizers which will make up some kind of programs, the meaning of which we will examine in chapter 4 (e.g. how to execute them).

Left[F, G] and Right[F, G] have been defined for functors F: C × D → E and G: C × D^{−} → E, where C, D and E are some categories. Remember the aim of CDT; we would like to define (or specify, or study) a category of data types. Therefore, C, D and E should somehow be related to this category. The simplest we can think of is that they are the product categories of this category and all the functors are in the form of C^{s} → C, where s is a sequence of variances (i.e. s ∈ Var^{∗}) and C^{v_{1}...v_{n}} =^{def} C^{v_{1}} ×⋯×C^{v_{n}}.

In order to simplify the presentation, let us use the vector notation and write, for example, F⃗ for a sequence of functors ⟨F_{1}, …, F_{n}⟩ where all of them have the same type C^{s} → C, that is, F⃗ is a functor of C^{s} → C^{n}.

From definition 3.1.3, for F⃗: C × C^{s} → C^{n} and G⃗: C × C^{−•s} → C^{n}, Left[F, G] is a functor

C^{s} → C and Right[F, G] is a functor C^{−•s} → C, where u • v_{1} … v_{n} =^{def} u • v_{1} … u • v_{n}.

Hence, we come to the definition of CDT declarations.

Definition 3.2.1: In CDT theory, there are two forms of declaring new functors. One is to define a functor L: C^{s} → C by

left object L(X⃗) with ψ is α⃗: F⃗ (L, X⃗) → G⃗(L, X⃗)

end object

(∗)

and the other is to define a functor R: C^{−•s} → C by

right object R(X⃗) with ψ is α⃗: F⃗ (R, X⃗) → G⃗(R, X⃗)

end object

where X⃗ is a sequence ⟨X_{1}, …, X_{n}⟩ of variables, ψ is the associated factorizer, α⃗ is a sequence ⟨α_{1}, …, α_{m}⟩ of the associated natural transformations, and F⃗ and G⃗ are sequences ⟨F_{1}, …, F_{m}⟩ and ⟨G_{1}, …, G_{m}⟩, respectively, of functors which we have as primitives or we have already defined and whose type is F_{i}: C × C^{s} → C and G_{i}: C × C^{−•s} → C, respectively. Semantically, L is Left[F⃗ , G⃗] and R is Right[F⃗ , G⃗]. We may call L left functor or left object and R right functor or right object. [] If we expand the definition of Left, (∗) defines for any C objects A⃗ = ⟨A_{1}, …, A_{n}⟩ an object L(A⃗) and a morphism

F⃗ (L(A⃗), A⃗)  α⃗A⃗  \overline{}G⃗(L(A⃗), A⃗),

and for any object B and a sequence of morphisms f⃗: F⃗ (B, A⃗) → G⃗(B, A⃗), ψ(f⃗) denotes the unique morphism which makes the following diagram commute.

[figure: F⃗ (L(A⃗), A⃗); α⃗A⃗; G⃗(L(A⃗), A⃗); L(A⃗); F⃗ (ψ(f⃗), A⃗); G⃗(ψ(f⃗), A⃗); ψ(f⃗); F⃗ (B, A⃗); f⃗; G⃗(B, A⃗); B]

In definition 3.2.1, it is not immediately clear what kind of F⃗ and G⃗ is allowed. We vaguely stated that they are primitive or have been defined already. In order to clarify this point, we go back to CSL and regard a CDT declaration as an extension of a given CSL signature.

Definition 3.2.2: Let ⟨Γ, Δ, Ψ⟩ be a CSL signature. A CDT declaration D ∈ Decl is given by the following BNF expression.

D : : = { left | right } object F (X_{1}, …, X_{n}) with ψ is
α_{1}: E_{1} → E′_{1}
…
α_{m}: E_{m} → E′_{m}

end object

where F is a new functor symbol, ψ is a new factorizer symbol, α_{1}, …, a_{m} are new natural transformation symbols, and E_{i} and E′_{i} (i = 1, …, m) are well-formed functorial expressions (under this signature ⟨Γ, Δ, Ψ⟩) whose variables are X_{1}, …, X_{n} and F (here we use F as a formal parameter like we use its function name inside a function body in PASCAL). []

We need to put restriction on the variance of F in the functorial expressions such that for each i = 1, …, m

1. the variance of F in E_{i} should be either covariant or free,

2. the variance of F in E′_{i} should also be either covariant or free, and

3. either the variance of F in E_{i} should be covariant or that in E′_{i} should be covariant.

We could have allowed F to be contravariant (as indeed the original definition of CDT did), but it turned out that the generality by contravariance was of very little use, so, because it simplifies the following argument, we restrict ourselves only to covariant functors. The third condition above is to make the extension consistent (each α_{i} should somehow relate to the functor we are declaring).

Let us calculate the variance of F. If the variance of λ(F, X_{1}, …, X_{n}).E_{i} is v_{i}s_{i} (v_{i} ∈ Var for the variance of F and s_{i} ∈ Var^{∗} for the variance of X_{1}, …, X_{n}) and that of λ(F, X_{1}, …, X_{n}).E′_{i} is v′_{i}s′_{i}, λ(F, X_{1}, …, X_{n}).E_{i} denotes a functor C^{v_{i}} × C^{s_{i}} → C and λ(F, X_{1}, …, X_{n}).E′_{i} denotes a functor C^{v′_{i}} × C^{s′_{i}} → C. The restriction above states that v_{i} ⊔ v′_{i} = +. From proposition 3.1.4, the variance of F in case that it is declared by a left CDT declaration should be

⨆_{i=1}^{m} s_{i} ⊔ − • s′_{i},  (∗)

and in case that it is declared by a right one, the variance should be

⨆_{i=1}^{m} − • s_{i} ⊔ s′_{i},  (∗∗)

where Var^{∗} is a partially ordered set with the ordering given by u_{1} … u_{n} ⊑ v_{1} … v_{n} if and only if u_{1} ⊑ v_{1}, … and u_{n} ⊑ v_{n}.

Definition 3.2.2 (continued): A CDT declaration gives an extension of CSL signature.

⟨Γ, Δ, Ψ⟩ ↪ ⟨Γ ∪ { F }, Δ ∪ { α_{1}, …, α_{m} }, Ψ ∪ { ψ }⟩

where the variance of F is given by (∗) or (∗∗), the type of α_{i} is

λ(X_{1}, …, X_{n}).E_{i}[F (X_{1}, …, X_{n})/F] →^{·} λ(X_{1}, …, X_{n}).E′_{i}[F (X_{1}, …, X_{n})/F],

and the type of ψ is

\frac{f_{i}: λ(X, X_{1}, …, X_{n}).E_{i}[X/F] → λ(X, X_{1}, …, X_{n}).E′_{i}[X/F] (i = 1, …, m)}{ψ(f_{1}, …, f_{m}): λ(X, X_{1}, …, X_{n}).F (X_{1}, …, X_{n}) → λ(X, X_{1}, …, X_{n}).X}

by a left CDT declaration and

\frac{f_{i}: λ(X, X_{1}, …, X_{n}).E_{i}[X/F] → λ(X, X_{1}, …, X_{n}).E′_{i}[X/F] (i = 1, …, m)}{ψ(f_{1}, …, f_{m}): λ(X, X_{1}, …, X_{n}).X → λ(X, X_{1}, …, X_{n}).F (X_{1}, …, X_{n})}

by a right one. []

We will see in section 3.4 a CDT declaration as a CSL theory extension so that the semantics of a CDT declaration can be given by a CSL structure.

3.3 Examples of Categorical Data Types

In this section, we will present several examples of categorical data types declared by

left object F (X_{1}, …, X_{n}) with ψ is

α_{1}: E_{1} → E′_{1}
…
α_{m}: E_{m} → E′_{m}

end object

(∗)

for left objects and by

right object F (X_{1}, …, X_{n}) with ψ is

α_{1}: E_{1} → E′_{1}
…
α_{m}: E_{m} → E′_{m}

end object

(∗∗)

for right objects.

3.3.1 Terminal and Initial Objects

Let us start with an empty CSL signature ⟨∅, ∅, ∅⟩. The simplest case of (∗) and (∗∗) is when n = m = 0. If we consider the case when n = m = 0 in (∗∗), we get the declaration of the terminal object.

right object 1 with ! end object

(We omitted the keyword ‘is’ to make the declaration look nicer.) From the definition, this defines an object ‘1’ and for any object A there is a unique morphism ‘!’ from A to ‘1’.

A  !  \overline{}1

Therefore, it really is the terminal object.

Dually, if we change the keyword ‘right’ to ‘left’ in the definition of the terminal object, we get the definition of the initial object.

left object 0 with !! end object

The factorizer ‘!!’ gives a unique morphism from ‘0’ to any object A.

0  !! \overline{}A

3.3.2 Products and CoProducts

Next, we define products and coproducts. The binary product functor can be declared as the following right object.

right object prod(X, Y) with pair is pi1: prod → X

pi2: prod → Y

end object

From definition 3.2.2, this defines a functor symbol ‘prod’ whose variance is ‘++’ (i.e. covariant in both arguments), two natural transformation symbols ‘pi1’ and ‘pi2’ whose types are

pi1: λ(X, Y).prod(X, Y) →^{·} λ(X, Y).X

pi2: λ(X, Y).prod(X, Y) →^{·} λ(X, Y).Y

and a factorizer symbol ‘pair’ whose type is

\frac{f: λ(Z, X, Y).Z → λ(Z, X, Y).X g: λ(Z, X, Y).Z → λ(Z, X, Y).Y}{pair(f, g): λ(Z, X, Y).Z → λ(Z, X, Y).prod(X, Y)} .

If we write this down in a more understandable way, it becomes the familiar definition of the binary product, that is ‘prod’ has two unit morphisms

[figure: A; prod(A, B); B; pi1; pi2]

and pair(f, g) gives the unique morphism for any morphisms f: C → A and g: C → B such that the following diagram commutes.

[figure: A; prod(A, B); B; pi1; pi2; C; f; g; pair(f, g)]

Note that the CDT declaration of the binary product functor is very similar to the ‘Prod’ theory in CLEAR defined in 3.1. One of the differences is that in CLEAR ‘pair’ is treated as a function in the same class as ‘pi1’ and ‘pi2’ but in CDT ‘pair’ is quite different from ‘pi1’ and ‘pi2’. Another one is that in CLEAR ‘Prod’ is declared as the initial algebra so it is close to CDT’s left object but in CDT ‘prod’ is naturally a right object because the product functor is the right adjoint of the diagonal functor.

Dually, we can define the binary coproduct functor as a left object.

left object coprod(X, Y) with case is in1: X → coprod in2: Y → coprod

end object

Again, this declaration looks very close to the one in CLEAR (defined in section 3.1), but note that we have ‘case’ in CDT so that we can use it to write programs or to specify some properties.

Just writing the situation as a diagram,

[figure: A; coprod(A, B); B; in1; in2; C; f; g; case(f, g)]

3.3.3 Exponentials

One of the objections against algebraic specification methods is that it cannot handle function spaces. CDT’s declaration mechanism looks very close to that of algebraic specification methods, but CDT is based on category theory not on many-sorted algebras, and in category theory function spaces can be defined as exponentials. For objects A and B, the exponential of B by A is written as exp(A, B)^{5} satisfies the following natural isomorphism.

Hom_{C}(prod(C, A), B) ≃ Hom_{C}(C, exp(A, B))

In other words, The functor exp(A, · ) is the right adjoint of prod( · , A). We write ‘curry’ for the factorizer and ‘eval’ for the counit natural transformation. Then, for any object C and any morphism f: prod(C, A) → B, curry(f) is the unique morphism from exp(A, B) to C such that the following diagram commutes.

[figure: C; exp(A, B); curry(f); prod(C, A); prod(exp(A, B), A); B; prod(curry(f), I); f; eval]

5Many category theory books use the notation B^{A} for the exponential of B by A.

The reason why the exponentials are function spaces is that their global elements are just morphisms.^{6}

Hom_{C}(1, exp(A, B)) ≃ Hom_{C}(prod(1, A), B) ≃ Hom_{C}(A, B)

Let us write down the definition as a CDT declaration. Assume a CSL signature ⟨Γ, Δ, Ψ⟩ which contains the definition of the binary product functor as we defined in subsection 3.3.2. Then, the exponential functor can be declared as follows.

right object exp(X, Y) with curry is eval: prod(exp, X) → Y

end object

This is so far the most complicated CDT declaration. In the previous examples, functorial expressions E_{i} and E′_{i} in (∗) and (∗∗) are all simply variables. From definition 3.2.2, the CDT declaration above defines a functor symbol ‘exp’ of type −+, a natural transformation ‘eval’ of type

λ(X, Y).prod(exp(X, Y), X) →^{·} λ(X, Y).Y

and a factorizer ‘curry’ of type

\frac{f: λ(Z, X, Y).prod(Z, X) → λ(Z, X, Y).Y}{curry(f): λ(Z, X, Y).Z → λ(Z, X, Y).exp(X, Y)} .

These types are what we expect them to be from the exponential adjunction. Let us once more convince ourselves that the semantics by F, G-dialgebras really defines the exponentials. ⟨exp(A, B), eval_{A,B}⟩ is the final F, G-dialgebra where F (C) =^{def} prod(C, A) and G(C) =^{def} B. This means that, for any ⟨C, f⟩ where C is an object and f is a morphism of F (C) → G(C), curry(f) is the unique morphism of

⟨exp(A, B), eval_{A,B}⟩ → ⟨C, f⟩.

From definition 3.1.2 of F, G-dialgebras, curry(f) is the unique morphism C → exp(A, B) which makes the following diagram commute.

[figure: F (C) = prod(C, A); B = G(C); f; F (exp(A, B)) = prod(exp(A, B), A); B = G(exp(A, B)); eval_{A,B}; F (curry(f)) = prod(curry(f), I); I = G(curry(f))]

This is exactly the condition of ‘exp’ being the exponential functor.

6A global element of an object A is a morphism from the terminal object to A.

The declaration of the exponential functor in CDT very much looks like a declaration in a algebraic specification language (e.g. in CLEAR), but, as is well-known, we cannot define function spaces as algebras. The essential difference lies in that ‘exp’ is a right object, in other words, defined by the terminal data constraint rather than the initial one which CLEAR uses and in the availability of the factorizer ‘curry’. If we define ‘curry’ as an ordinary function (or an ML function), its type is

(C × A → B) → (C → (A → B))

and this could never be a type of algebraic functions (i.e. functions defined by algebraic specification methods).

3.3.4 Natural Number Object

As we have already shown that the natural number object can be given by ‘Left’, let us write it down as a CDT declaration. Although we can define the natural number object if we have only the terminal object, it is often very convenient to assume that a CSL signature ⟨Γ, Δ, Ψ⟩ contains not only the terminal object but also the product functor and the exponential functor. The declaration of the natural number object as a CDT is

left object nat with pr is zero: 1 → nat succ: nat → nat

end object

which defines a constant functor (i.e. an object) ‘nat’ with two morphisms ‘zero’ and ‘succ’.

[figure: 1; nat; zero; succ]

In addition, the factorizer ‘pr’ (standing for primitive recursion) gives for any morphisms f: 1 → A and g: A → A a unique morphism pr(f, g): nat → A such that the following diagram commutes.

As is well-known (e.g. [Goldblatt 79] chapter 13), ‘pr’ provides us to define any primitive recursive function.

[figure: 1; zero; nat; succ; nat; f; pr(f, g); pr(f, g); A; A; g]

CHAPTER 3. CATEGORICAL DATA TYPES 61 Definition 3.3.1: For a category C with the natural number object ‘nat’, the terminal object ‘1’ and the binary product functor ‘prod’, a morphism f is primitive recursive (on natural numbers) if it can be generated after finitely many steps by means of the following rules:

1. f = I_{nat}: nat → nat,

2. f = zero: 1 → nat,

3. f = succ: nat → nat,

4. f = pi1: prod(nat, nat) → nat,

5. f = pi2: prod(nat, nat) → nat,

6. f = g ∘ pair(h, k): A → nat for primitive recursive morphisms g: prod(nat, nat) → nat, h: A → nat and k: A → nat,

7. f = g ∘ prod(h, k): prod(A, B) → nat for primitive recursive morphisms g: prod(nat, nat) → nat, h: A → nat and k: B → nat, and

8. f: prod(nat, A) → nat satisfying (a) f ∘ pair(zero ∘!, I) = g, and

(b) f ∘ pair(succ ∘ pi1, pi2) = h ∘ pair(f, I)

for primitive recursive g: A → nat and h: prod(nat, prod(nat, A)) → nat. [] This is a straight copy of the standard definition of primitive recursive functions on natural numbers. Proposition 3.3.2: If a cartesian closed category C has the natural number object, it has all the primitive recursive morphisms. Proof: It is suffice to show that there exists a morphism f: prod(nat, A) → nat for any morphisms g: A → nat and h: prod(nat, prod(nat, A)) → nat such that

1. f ∘ pair(zero ∘!, I) = g, and

2. f ∘ pair(succ ∘ pi1, pi2) = h ∘ pair(f, I). There is a morphism k: nat → prod(exp(A, nat), nat) such that the following diagram commutes. where g′ and h′ are

[figure: 1; nat; nat; prod(exp(A, nat), nat); prod(exp(A, nat), nat); zero; succ; k; k; g′; h′]

g′ =^{def} pair(curry(g ∘ pi2), zero)
h′ =^{def} pair( curry(h ∘ pair( eval ∘ pair( pi2,
pi1 ∘ pi1),
pi2 ∘ pi1)),
succ ∘ pi2).

Therefore, k is pr(g′, h′). Then, f =^{def} eval ∘ prod(pi1 ∘ k, I). We can easily show that this is what we wanted. []

For example, the morphism ‘add’ corresponding to the addition function of natural numbers can be given as

add =^{def} eval ∘ prod(pr(curry(pi2), curry(succ ∘ eval)), I).

It corresponds to the following usual definition of ‘add’.

add(0, y) = y
add(x + 1, y) = add(x, y) + 1

Furthermore, we can easily prove categorically that ‘add’ satisfies familiar laws like commutativity (categorically add ∘ pair(pi2, pi1) = add) and so on.

3.3.5 Lists

We have defined the data type of natural numbers in the previous subsection. Another algebraic data type which is often used in programming is the data type of lists. In CDT, the data type of lists is defined as follows:

left object list(X) with prl is nil: 1 → list cons: prod(X, list) → list

end object

We needed to assume a CSL signature having the terminal object and the product functor. The declaration above defines a one argument covariant functor ‘list’, two natural transformations

nil: λ(X).1 →^{·} λ(X).list(X) and cons: λ(X).prod(X, list(X)) →^{·} λ(X).list(X)

and a factorizer ‘prl’ (standing for primitive recursion on list) whose type is

\frac{f: λ(Y, X).1 → λ(Y, X).Y g: λ(Y, X).prod(X, Y) → λ(Y, X).Y}{prl(f, g): λ(Y, X).list(X) → λ(Y, X).Y} .

As usual, we can express the situation as a diagram.

[figure: 1; list(A); prod(A, list(A)); B; prod(A, B); nil; cons; f; prl(f, g); prod(I, prl(f, g)); g]

A global element of list(A) is normally constructed from ‘nil’ and ‘cons’. For example, list(nat) has

cons ∘ pair(succ ∘ zero, cons ∘ pair(succ ∘ succ ∘ zero, nil))

as a global element (in plain words, this element is the list of 1 and 2). ‘nil’ and ‘cons’ are usually called constructors of ‘list’. We can see in general to define an algebraic CDT by listing its constructors. Destructors are defined using factorizers. In the case of ‘list’, ‘hd’ (head) and ‘tl’ (tail) can be defined as follows.

hd =^{def} prl(in2, in1 ∘ pi1)

tl =^{def} coprod(pi2, I) ∘ prl(in2, in1 ∘ prod(I, case(cons, nil)))

Note that we have to define ‘hd’ and ‘tl’ as total functions (in a sense). The type of ‘hd’ is list(A) → coprod(A, 1) and is not list(A) → A. The type of ‘tl’ is also list(A) → coprod(list(A), 1). The type ‘1’ is for error (like ⊥ in a domain) and, for example, hd ∘ nil = in2.

As ‘list’ is a covariant functor, for a morphism f: A → B list(f): list(A) → list(B) transforms a list of A elements to a list of B elements by applying f to each element. For example, list(succ): list(nat) → list(nat) increments every element in a given list by one. In general, we have the following equations:

list(f) = prl(nil, cons ∘ prod(f, I))

list(f) ∘ nil = nil

list(f) ∘ cons ∘ pair(x, l) = cons ∘ pair(f ∘ x, list(f) ∘ l)

‘list’ corresponds to ‘map’ function in ML and ‘MAPCAR’ in LISP.

3.3.6 Final Co-Algebras (Infinite Lists and Co-Natural Number Object)

The objects we defined in the preceding subsections are all familiar either in category theory or in programming languages. Particularly, we have seen in subsection 3.3.4 and 3.3.5 the natural number object and the data type of lists, which are typical initial algebras. Recently, several works have been done about final coalgebras, which are the dual of initial algebras (see [Arbib and Manes 80]). From their symmetry of CDT declarations, we can easily define final coalgebras in CDT as well as initial algebras.

Let us dualize the declaration of the natural number object defined in subsection 3.3.4 by

left object nat with pr is zero: 1 → nat succ: nat → nat

end object

If we simply replace ‘left’ by ‘right’ and change the direction of arrows, we get

right object conat with copr is cozero: nat → 1 cosucc: nat → nat

end object

Unfortunately, this is not an exciting object. We can prove that ‘conat’ is isomorphic to the terminal object as follows: from the uniqueness of terminal objects up to isomorphism in any category, we simply need to show that ‘1’ is the terminal F, G-dialgebra for these particular F and G, that is, for any object A and morphisms f: A → 1 and g: A → A, there exists a unique morphism h: A → 1 such that the following diagram commutes.

[figure: A; g; A; h; h; f; 1; 1; 1; cosucc; cozero]

Indeed, we have this unique morphism A → 1 because ‘1’ is the terminal object and the above diagram trivially commutes.

Although the exact dual of the natural number object is not an interesting thing, we can modify it to get a CDT data type of infinite lists.

right object inflist(X) with fold is head: inflist → X tail: inflist → inflist

end object The diagram of explaining ‘inflist’ is

[figure: B; B; fold(f, g); fold(f, g); f; inflist(A); inflist(A); A; tail; head; g]

Since the functor ‘inflist’ is not so familiar in category theory or in conventional programming languages, let us find out what it is in the category of sets. We expect it to be a set of infinite lists in some sense.

Proposition 3.3.3: In the category of sets, for a set A, inflist(A) is the following set of ω-infinite sequences of elements in A.

{ (x_{0}, x_{1}, …, x_{n}, …) | x_{i} ∈ A }

Proof: We define ‘head’ and ‘tail’ as follows:

head((x_{0}, x_{1}, …, x_{n}, …)) =^{def} x_{0}

tail((x_{0}, x_{1}, …, x_{n}, …)) =^{def} (x_{1}, x_{2}, …, x_{n+1}, …)

Let fold(f, g)(x) be a sequence (h_{0}(x), h_{1}(x), …, h_{n}(x), …) for functions f: B → A and g: B → B. The commutativity of the diagram above forces the following equations.

\begin{matrix}h_{0}(x) = f(x) \\ (h_{1}(x), h_{2}(x), …, h_{n+1}(x), …) = (h_{0}(x), h_{1}(x), …, h_{n}(x), …) \end{matrix}

Therefore, fold(f, g)(x) is uniquely determined as

fold(f, g)(x) =^{def} (f(x), f(g(x)), …, f(g^{n}(x)), …) []

Hence, at least in the category of sets, inflist(A) is really the data type of infinite lists of A elements.

More generally,

Proposition 3.3.4: In a cartesian closed category C with the natural number object, inflist(A) is isomorphic to exp(nat, A). Proof: Let us define h: exp(nat, A) → inflist(A) to be the fill-in morphism of the following diagram. where ‘head′’ and ‘tail′’ are

[figure: exp(nat, A); tail′; exp(nat, A); h; h; head′; inflist(A); tail; inflist(A); head; A]

head′ =^{def} eval ∘ pair(I, zero ∘!), tail′ =^{def} curry(eval ∘ prod(I, succ)).

We define h′: inflist(A) → exp(nat, A) to be

h′ =^{def} curry(eval ∘ pair(pr(curry(head ∘ pi2), exp(tail, I)) ∘ pi2, pi1)).

After some calculation, we can show that h ∘ h′ = I and h′ ∘ h = I, so inflist(A) is isomorphic to exp(nat, A). []

This proposition tells us that

inflist(A) ≅ A × A × ⋯ × A × ⋯ ≅ ∏_{i=1}^{∞} A.

Indeed, this is the dual of ∑_{i=1}^{∞} A, the special case of which is the natural number object, nat ≅ ∑_{i=1}^{∞} 1.

We started this subsection by considering the dual of the natural number object. It led us to the CDT data type of infinite lists. We still have a different question whether there is a final coalgebra which resembles a data type of natural numbers. The answer is yes. The following right object defines a CDT data type of natural numbers plus alpha.

right object conat with copr is

pred: conat → coprod(1, conat) end object

The situation can be written as a diagram

[figure: A; f; coprod(1, A); copr(f); coprod(1, copr(f)); conat; pred; coprod(1, conat)]

The natural transformation ‘pred’ is the predecessor function and there is a morphism from ‘nat’ to ‘conat’ given by

copr(pr(in1, in2 ∘ case(zero, succ)))

which we expect to be injective, but so far the author has been able neither to prove it nor to give a counter example. Note that there is always a morphism from the left object to its corresponding right object. ‘Conat’ has an interesting extra element, namely the infinity (∞). The ground element to denote it is

infinity =^{def} copr(in2)

It is easy to prove that the predecessor of the infinity is itself (i.e. pred ∘ infinity = in2 ∘ infinity).

In the category of sets, ‘conat’ is really the set of natural numbers and the infinity.

Proposition 3.3.5: In Set, ‘conat’ is ‘nat ∪ { ∞ }’. Proof: The predecessor function is defined as usual. Roughly speaking, for any function f: A → coprod(1, A), copr(f)(x) is the number of applications of f to x to get the element of 1

copr(f)(x) = n where f^{n}(x) ∈ 1,

and, if it never results in the element of 1, copr(f)(x) = ∞. We can easily show that this is the unique function which makes the ‘conat’ diagram commute. []

Therefore, in the category of sets, ‘conat’ is isomorphic to ‘nat’, but this is not the case for all the categories. There are some categories where ‘conat’ and ‘nat’ are not isomorphic.

Proposition 3.3.6: In category TRF of subsets of natural numbers as objects and total recursive functions as morphisms, there exists the natural number object but does not exist the co-natural number object. Proof: TRF’s terminal object, initial object, product functor and coproduct functor are all the same as those of Set. For example, injections ‘in1’ and ‘in2’ for coprod(A, B) are trivially total and recursive, and for any two total recursive functions f: A → C and g: B → C case(f, g) is also total recursive function. We can write it down as a kind of program.

case(f, g)(x) =^{def} if x ∈ A then f(x)
else g(x)

The natural number object ‘nat’ in TRF is also the ordinary set of natural numbers. ‘Zero’ and ‘succ’ are total recursive functions from the very definition of recursive functions and for f: 1 → A and g: A → A of total recursive functions, pr(f, g) can be written as the following program.

pr(f, g)(n) =^{def} if n = 0 then f()
else g(pr(f, g)(n − 1))

which defines a total recursive function.

However, we cannot have the co-natural number object in TRF. The program of copr(f) for a total recursive function f: A → coprod(1, A) can only be

copr(f)(x) =^{def} if f(x) ∈ 1 then 0

else copr(f)(f(x)) + 1

which is recursive but not total. []

There is also a category which has both ‘nat’ and ‘conat’ and in which they are nonisomorphic. We will show this in chapter 4.

From the point of view of finding fixed points of functors, ‘nat’ is the initial fixed point of F (X) =^{def} 1 + X and ‘conat’ is the final fixed point of the same functor.

3.3.7 Automata

The declarations of initial algebras and final coalgebras do not use the full power of the CDT declaration mechanism. Their unit and counit natural transformations always have the form

α: E → F

for initial algebras and have the form

α: F → E

for final coalgebras, where E is any functorial expression but F is a variable (more specially, the variable which denotes the object we declare). Therefore, all we are doing is just listing constructors for initial algebras and listing destructors for final coalgebras. We will see what kinds of form define sensible functors in section 3.5. So far, the only exception was the exponentials. We will see another example in this subsection.

One of the interesting applications of category theory to computer science is to automata theory. [Arbib and Manes 75] presents the category Dyn(I) of I-dynamics whose object is

Q × I  δ  \overline{}Q,

where Q is the set of states, I is the set of inputs and δ is a dynamics which is a function determining the next state of the automaton according to the current state and input.

From this, we can construct a categorical data type of automata.

right object dyn(I) with univ is next: prod(dyn, I) → dyn

end object

Note that our dyn(I) for an object I is just an object; it is not a category like Dyn(I) is. The diagram which explains this right object is

[figure: prod(Q, I); δ; Q; prod(univ(δ), I); univ(δ); prod(dyn(I), I); next; dyn]

For any dynamics δ: prod(Q, I) → Q and an initial state q_{0}: 1 → Q, we get an automaton

1  \overline{}univ(δ) ∘ q_{0} dyn(I)

as a global element of dyn(I). Though we can put this automaton into the next state by applying ‘next’, we are never ever able to see its behaviour from the outside. Moreover, because of this non-observability, we can easily prove that dyn(I) is in fact isomorphic to the terminal object. In order to make ‘dyn’ a more sensible object, we need to add an output function. The new categorical data type of automata is^{7}

right object dyn′(I, O) with univ′ is next′: prod(dyn′, I) → dyn′ output′: dyn′ → O

end object

For any dynamics δ: prod(Q, I) → Q, any output function β: Q → O and an initial state q_{0}: 1 → Q, we have a global element in dyn′(I, O)

1  \overline{}univ′(δ, β) ∘ q_{0} dyn′(I, O).

We can obtain its next state by applying ‘next′’ and its output by ‘output′’. In addition, the following proposition holds.

Proposition 3.3.7: In a cartesian closed category, the categorical data type of Moore automata, dyn′(I, O), is isomorphic to exp(list(I), O). Proof: By defining two morphisms between them and proving that they form an isomorphism. []

3.3.8 Obscure Categorical Data Types

We have defined more or less familiar data types as categorical data types in the preceding subsections. One might ask whether CDT can define any data types which are unable to be defined in other languages or methods. The data type of automata is such an example and we can invent similar examples more, but still they are familiar (or we are just trying to express our familiar data types in CDT). In fact, CDT allows us very obscure data types, some of which may not be conceptualized in the human brain (at least not in the author’s brain).

From the prime requirement of CDT, it can define right and left adjoint functors of any existing functors, and in subsection 3.3.5, we defined ‘list’ as a covariant functor, so that we can declare its left and right adjoint functors in CDT as follows.

left object ladjlist(X) with ψ is α: X → list(ladjlist)

end object right object radjlist(X) with ψ′ is α′: list(radjlist) → X

7The original definition we used was

right object dyn′(I, O) with univ′ is

next′: prod(dyn′, I) → prod(dyn′, O)

end object which gave us the categorical data type of Mealy automata. The current definition gives us the data type of Moore automata.

end object

Some questions arise immediately after defining these data types: are they familiar data types, and are they in any way useful? The answers to the both questions are unfortunately negative. For the left adjoint,

Proposition 3.3.8: In a cartesian closed category, ‘ladjlist(A)’ for any object A is isomorphic to the initial object. Proof: It is easy to show that the initial object makes the characteristic diagram of ‘ladjlist’ commute. Note that in a cartesian closed category ‘list(0)’ is isomorphic to the terminal object so that the unit morphism of ‘ladjlist’ is the unique morphism to the terminal object. []

The right adjoint functor is more harmful than the left one.

Proposition 3.3.9: A cartesian closed category with ‘radjlist’ degenerates (i.e. all the objects are isomorphic). Proof: We have the following morphism from the initial object.

1 ⟶^{nil} list(radjlist(0)) ⟶^{α′} 0

Then, it is easy to show that the terminal object is isomorphic to the initial one. This further implies that any object in the category is isomorphic to the initial object.

A ≅ prod(A, 1) ≅ prod(A, 0) ≅ 0 []

Most of the left and right adjoint functors of conventional data types follow the same pattern as ‘list’, that is, they are either trivial or destructive, so they are useless.

Hence, a natural question to ask ourselves is that what kind of categorical data types are useful. But what is the formal criteria of useful data types? We have not yet defined this. We will come back to this in chapter 4 and see it from a point of view of computability of categorical data types.

3.4 Semantics of Categorical Data Types

In definition 3.2.2, we associated a CDT declaration to a CSL signature extension (an injective morphism in CSig). In this section, we will see it as a CSL theory extension and give the precise semantics of CDT declarations.

First, from our informal intention of CDT declarations we have to figure out the CSL statements which characterize them. A CDT declaration

left object L(X_{1}, …, X_{n}) with ψ is

α_{1}: E_{1} → E′_{1}
⋯
α_{m}: E_{m} → E′_{m}

end object is the syntactic form of defining the functor L = Left[F⃗ , G⃗], where F⃗ and G⃗ are corresponding functors for E_{1}, …, E_{m} and E′_{1}, …, E′_{m}, respectively. ⟨L(A⃗), α⃗⟩ is the initial object of DAlg(F⃗ , G⃗) and ψ is its mediating morphism, that is, for any morphisms f⃗: F⃗ (B, A⃗) → G⃗(B, A⃗), ψ(f⃗) gives a unique morphism from L(A⃗) to B such that the following diagram commutes.

[figure: F⃗ (L(A⃗), A⃗); α⃗A⃗; G⃗(L(A⃗), A⃗); L(A⃗); F⃗ (ψ(f⃗), A⃗); G⃗(ψ(f⃗), A⃗); ψ(f⃗); F⃗ (B, A⃗); f⃗; G⃗(B, A⃗); B]

The commutativity of this diagram can be expressed as the following equation:

G⃗(ψ(f⃗), A⃗) ∘ α⃗ = f⃗ ∘ F⃗ (ψ(f⃗), A⃗),  (∗)

and the uniqueness can be expressed as the following conditional equation:

G⃗(h, A⃗) ∘ α⃗ = f⃗ ∘ F⃗ (h, A⃗) ⇒ h = ψ(f⃗)  (∗∗)

The two equations say everything about L, α⃗ and ψ. Let us now translate them to CSL statements in ⟨Γ∪{L}, Δ∪{α_{1}, …, α_{m}}, Ψ∪{ψ}⟩ so as to give complete description of the CDT declaration above in CSL. (∗) corresponds to the following m CSL equations:

E′_{i}[ψ(f_{1}, …, f_{m})/L] ∘ α_{i} = f_{i} ∘ E_{i}[ψ(f_{1}, …, f_{m})/L]^{8}  (LEQ_{i})

(i = 1, …, m) and (∗∗) corresponds to the following conditional CSL equation.

E′_{1}[g/L] ∘ α_{1} = f_{1} ∘ E_{1}[g/L] ∧ …

∧ E′_{m}[g/L] ∘ α_{m} = f_{m} ∘ E_{m}[g/L] ⇒ g = ψ(f_{1}, …, f_{m}) (LCEQ)

In addition, we should have a CSL equation expressing functors by factorizers and natural transformations. We can extract such an equation from proposition 3.1.4.

L(h_{1}, …, h_{n}) =

ψ(E′_{1}[h_{i}/X_{i}] ∘ α_{1} ∘ E_{1}[h_{i}/X_{i}], …, E′_{m}[h_{i}/X_{i}] ∘ α_{m} ∘ E_{m}[h_{i}/X_{i}])^{9} (LFEQ)

Therefore, the semantics of CDT declaration can be given as a CSL theory extension as follows.

8E_{i}[ψ(f_{1}, …, f_{m})/L] means replacing the variable L by ψ(f_{1}, …, f_{m}) and replacing the other variables X_{1}, …, X_{n} by the identities, that is it is a shorthand for

E_{i}[ψ(f_{1}, …, f_{m})/L, I/X_{1}, …, I/X_{n}].

9E_{1}[h_{i}/X_{i}] is a shorthand for E_{1}[I/L, h_{1}/X_{1}, …, h_{n}/X_{n}].

Definition 3.4.1: Given a CSL theory ⟨Γ, Δ, Ψ, Θ⟩, a CDT declaration

left object L(X_{1}, …, X_{n}) with ψ is

α_{1}: E_{1} → E′_{1}
⋯
α_{m}: E_{m} → E′_{m}

end object,

where E_{i} and E′_{i} (i = 1, …, m) are CSL functorial expressions over ⟨Γ, Δ, Ψ⟩ whose variables are X_{1}, …, X_{n} and L, is associated with a CSL theory morphism

σ_{L}: ⟨Γ, Δ, Ψ, Θ⟩ → ⟨Γ ∪ {L}, Δ ∪ {α_{1}, …, α_{m}}, Ψ ∪ {ψ},
Θ ∪ {LEQ_{1}, …, LEQ_{m}, LCEQ, LFEQ}⟩

where the types of L, α_{1}, …, α_{m} and ψ are as given in definition 3.2.2. Dually, we can associate to a right object R

right object R(X_{1}, …, X_{n}) with ψ is

α_{1}: E_{1} → E′_{1}
⋯
α_{m}: E_{m} → E′_{m}

end object,

a CSL theory morphism σ_{R}.

σ_{R}: ⟨Γ, Δ, Ψ, Θ⟩ → ⟨Γ ∪ {R}, Δ ∪ {α_{1}, …, α_{m}}, Ψ ∪ {ψ},
Θ ∪ {REQ_{1}, …, REQ_{m}, RCEQ, RFEQ}⟩

where REQ_{i}, RCEQ and RFEQ are

α_{i} ∘ E_{i}[ψ(f_{1}, …, f_{m})/R] = E′_{i}[ψ(f_{1}, …, f_{m})/R] ∘ f_{i}  (REQ_{i})
α_{1} ∘ E_{1}[g/R] = E′_{1}[g/R] ∘ f_{1} ∧ …
∧ α_{m} ∘ E_{m}[g/R] = E′_{m}[g/R] ∘ f_{m} ⇒ g = ψ(f_{1}, …, f_{m}) (RCEQ)
R(h_{1}, …, h_{n}) =
ψ(E′_{1}[h_{1}/X_{i}] ∘ α_{1} ∘ E_{1}[h_{i}/X_{i}], …, E′_{m}[h_{i}/X_{i}] ∘ α_{m} ∘ E_{m}[h_{i}/X_{i}]) (RFEQ)

[]

Example 3.4.2: Let ⟨Γ, Δ, Ψ, Θ⟩ be the CSL theory of cartesian closed categories (see examples 2.2.2 and 2.5.3). On top of this, as we have seen in section 3.3.4, we can define a natural number object by

left object nat with pr is zero: 1 → nat succ: nat → nat

end object.

The CSL statements characterizing this object are

pr(f, g) ∘ zero = f (LEQ_{nat,1}) pr(f, g) ∘ succ = g ∘ pr(f, g) (LEQ_{nat,2}) h ∘ zero = f ∧ h ∘ succ = g ∘ h ⇒ h = pr(f, g) (LCEQ_{nat})

The CSL extension σ_{nat} associated with the declaration above is:

⟨Γ, Δ, Ψ⟩ ⟶^{σ_{nat}} ⟨Γ ∪ {nat}, Δ ∪ {zero, succ}, Ψ ∪ {pr},
Θ ∪ {LEQ_{nat,1}, LEQ_{nat,2}, LCEQ_{nat}}⟩ []

Thus, each CDT declaration can be associated with a CSL theory extension. This can be thought as a semantics of CDT declarations. However, it is sometimes convenient to regard their semantics to be real categories.

Definition 3.4.3: A sequence of CDT declarations D_{1}, …, D_{l} defines a sequence of CSL theory extensions starting from the empty CSL theory.

⟨∅, ∅, ∅, ∅⟩ ⟶^{σ_{D_{1}}} ⟨Γ_{1}, Δ_{1}, Ψ_{1}, Θ_{1}⟩ ⟶^{σ_{D_{2}}} ⋯ ⟶^{σ_{D_{l}}} ⟨Γ_{l}, Δ_{l}, Ψ_{l}, Θ_{l}⟩

We define a CSL structure of the CDT declaration sequence D_{1}, …, D_{l} to be a category which is a CSL theory structure of ⟨Γ_{l}, Δ_{l}, Ψ_{l}, Θ_{l}⟩, and the free structure of D_{1}, …, D_{l} to be the free category of this CSL theory (see section 2.6). []

If we do not rely on any ways of defining functors other than CDT declarations and if we do not accept any pre-defined functors, it is inevitable to start with the empty CSL theory. We have defined cartesian closed categories as a CSL theory in examples 2.2.2 and 2.5.3, but we can do so in CDT starting from the empty theory by just declaring the terminal object (see subsection 3.3.1), products (see subsection 3.3.2) and exponentials (see subsection 3.3.3). The advantage of the latter is that we neither need to think about equations nor need to do tedious typing of functors, natural transformations or factorizers. These things come out automatically, so it is easy to define categories and there is less chance to make mistakes.

We have introduced CDT declarations from Left and Right, but we could not connect them formally. Now, after having models of CDT as categories, we can do so.

Proposition 3.4.4: Let ⟨C, ξ⟩ be a CSL structure of a CDT declaration sequence D_{1}, …, D_{l}. If D_{i} is

left object L(X_{1}, …, X_{n}) with ψ is

α_{1}: E_{1} → E′_{1}
⋯
α_{m}: E_{m} → E′_{m}

end object

then ξL = Left(F⃗ , G⃗) where

\begin{matrix}F⃗ =^{def} ⟨ξλ(L, X_{1}, …, X_{n}).E_{1}, …, ξλ(L, X_{1}, …, X_{n}).E_{m}⟩ \\ G⃗ =^{def} ⟨λ(L, X_{1}, …, X_{n}).E′_{1}, …, λ(L, X_{1}, …, X_{n}).E′_{m}⟩. \end{matrix}

CHAPTER 3. CATEGORICAL DATA TYPES 74

Name  CDT Declaration  CSL Statements

Terminal right object 1 with !

end object

f = !

Initial left object 0 with !! end object

f = !!

Products right object prod(X, Y) with pair is pi1: prod → X pi2: prod → Y

end object pi1 ∘ pair(f, g) = f pi2 ∘ pair(f, g) = g h = pair(pi1 ∘ h, pi2 ∘ h) prod(f, g) = pair(f ∘ pi1, g ∘ pi2)

Coproducts left object coprod(X, Y) with case is in1: X → coprod in2: Y → coprod

end object case(f, g) ∘ in1 = f case(f, g) ∘ in2 = g h = case(h ∘ in1, h ∘ in2) coprod(f, g) = case(in1 ∘ f, in2 ∘ g)

Exponentials right object exp(X, Y) with curry is

eval: prod(exp, X) → Y end object eval ∘ prod(curry(f),I) = f h = curry(eval ∘ prod(h,I)) exp(f, g) = curry(g ∘ eval ∘ prod(I, f))

NNO left object nat with pr is zero: 1 → nat succ: nat → nat

end object pr(f, g) ∘ zero = f pr(f, g) ∘ succ = g ∘ pr(f, g) h ∘ succ = g ∘ h ⇒ h = pr(h ∘ zero, g)

Lists left object list(X) with prl is nil: 1 → list cons: prod(X, list) → list

end object prl(f, g) ∘ nil = f prl(f, g) ∘ cons = prod(I, prl(f, g)) ∘ g h ∘ cons = prod(I, h) ∘ g ⇒

h = prl(h ∘ nil, g) list(f) = prl(nil, cons ∘ prod(f,I))

Infinite Lists right object inflist(X) with fold is head: inflist → X tail: inflist → inflist

end object head ∘ fold(f, g) = f tail ∘ fold(f, g) = fold(f, g) ∘ g tail ∘ h = g ∘ h ⇒ h = fold(head ∘ h, g) inflist(f) = fold(f ∘ head, tail)

Co-NNO right object conat with copr is

pred: conat → coprod(1, conat) end object pred ∘ copr(f) = coprod(I, copr(f)) ∘ f h ∘ pred = f ∘ coprod(I, h) ⇒

h = copr(f)

Automata right object dyn′(I, O) with univ′ is next′: prod(dyn′, I) → dyn′ output′: dyn′ → O

end object next′ ∘ prod(univ′(f, g),I) = univ′(f, g) ∘ f output′ ∘ univ′(f, g) = g next′ ∘ prod(h,I) = h ∘ f ⇒

h = univ′(f, output′ ∘ h)

Figure 3.1: CDT Objects

The similar thing holds for right CDT declarations. Proof: Trivial, because we set the CSL statements so that this proposition holds. []

Finally, in this section, let us summarize the objects we have defined in this chapter and their characteristic CSL statements in figure 3.1.

3.5 Existence of Left and Right

In section 3.1, we have introduced functors Left[F, G] and Right[F, G] with the condition which characterizes them, but we did not consider whether such functors exist or not. In this section, we study them mathematically and present a condition of the existence.

Let us recall the standard construction of initial T -algebras (see, for example, [Scott 76, Lehmann and Smyth 81]).

Proposition 3.5.1: For a ω-cocomplete category C (i.e. it has colimit of any ω-chain diagram) and an endo-functor T: C → C which is ω-cocontinuous (i.e. it preserves colimit of any ω-chain diagram), its initial T -algebra is given by the colimit of the following ω-chain diagram.^{10}

0 ⟶^{!!} T (0) ⟶^{T (!!)} T^{2}(0) ⟶^{T^{2}(!!)} ⋯ ⟶^{T^{n−1}(!!)} T^{n}(0) ⟶^{T^{n}(!!)} ⋯ []

As we presented in section 3.1, Left[F, G] is a generalization of initial T -algebras, where F is a functor of C × D → E and G is of C × D^{−} → E. We will reduce the existence problem of Left to that of corresponding T -algebras. For a D object A, from its definition ⟨Left[F, G](A), η_{A}⟩ is the initial object in the category DAlg(F ( · , A), G( · , A)), so

F (Left[F, G](A), A)  η_{A}  \overline{}G(Left[F, G](A), A)

Now, if G( · , A) has a left adjoint functor, say H( · , A): E → C, this morphism η_{A} has its one-to-one corresponding morphism

H(F (Left[F, G](A), A), A)  \overline{}Left[F, G](A).

This means that Left[F, G](A) is a T -algebra, where T (B) =^{def} H(F (B, A), A), and we naturally expect this T -algebra to be special. It really is the initial T -algebra, so we can formulate the following theorem.

Theorem 3.5.2: Let F: C × D → E and G: C × D^{−} → E be functors. If

1. C is ω-cocomplete,

2. for each D object A, G_{A} =^{def} G( · , A): C → E has a left adjoint H_{A}: E → C, and

3. for each D object A, F_{A} =^{def} F ( · , A): C → E is ω-cocontinuous,

then Left[F, G](A) exists in C and

Left[F, G](A) = colimit_{n}(H_{A} ∘ F_{A})^{n}(0)

Proof: Since a left adjoint is cocontinuous, T_{A} =^{def} H_{A} ∘ F_{A} is ω-cocontinuous if F_{A} is so. All we have to show is that the initial T_{A}-algebra gives the initial object of DAlg(F_{A}, G_{A}), and the rest follows from proposition 3.5.1.

Let the initial T_{A}-algebra be I paired with a morphism

H^{A}(F^{A}(I))  ι  \overline{}I.

any ordinal such that 1. T^{α+1}(0) = T (T^{α}(0)), and

10In general, this sequence might not converge at ω. In such a case, we may extend the sequence up to

2. T^{β}(0) = colimit_{α<β} T^{α}(0) for a limit ordinal β (treating 0 as a limit ordinal).

For an object ⟨B, f⟩ in DAlg(F_{A}, G_{A})

F^{A}(B)  f  \overline{}G^{A}(B)

we have to construct the unique morphism from I to B which makes a certain diagram commute. To do so, let us name the factorizer of the adjunction H_{A} ⟼ G_{A} ψ, that is, ψ is the natural isomorphism Hom_{C}(H_{A}(C), D) ⟶^{≅} Hom_{E}(C, G_{A}(D)). Then, ψ^{−1}(f) gives a T_{A}-algebra

H^{A}(F^{A}(B))  ψ^{−1}(f) \overline{}B

and since ⟨I, ι⟩ is the initial T_{A}-algebra, there exists a unique morphism g: I → B such that the following diagram commutes.

[figure: H_{A}(F_{A}(I)); ι; I; H_{A}(F_{A}(g)); g; H_{A}(F_{A}(B)); ψ^{−1}(f); B]  (∗)

The naturality of ψ converts this diagram to the following commutative diagram.

[figure: F_{A}(I); ψ(ι); G_{A}(I); F_{A}(g); G_{A}(g); F_{A}(B); f; G_{A}(B)]  (∗∗)

(i.e. ψ(g ∘ ι) = G_{A}(g) ∘ ψ(ι) and ψ(ψ^{−1}(f) ∘ H_{A}(F_{A}(g))) = f ∘ F_{A}(g)). That showed the existence of g. The uniqueness of g is no more difficult. If g: I → B satisfies (∗∗), then by applying ψ^{−1} we get (∗) back again and so there g should be unique. []

Example 3.5.3: Trivially, if E is C and G: C × D^{−} → C is the projection functor, G_{A} is the identity which has the left adjoint H_{A} which is also the identity functor. In this case, the above theorem is essentially stating the same thing as proposition 3.5.1. []

Example 3.5.4: Another simple case is that E is C × C and G_{A} is the diagonal functor. Its left adjoint is the binary coproduct functor. F_{A}: C → C × C can be decomposed into F′_{A} and F′′_{A} both of which are functors of C × D → C such that F_{A}(B) = ⟨F′_{A}(B), F′′_{A}(B)⟩. The theorem states that Left[F, G](A) is the initial T_{A}- algebra where T_{A}(B) =^{def} F′_{A}(B) + F′′_{A}(B). This explains that our natural number object in subsection 3.3.4 is the initial T -algebra where T (B) =^{def} 1 + B. []

Theorem 3.5.2 has its dual form for Right[F, G].

Theorem 3.5.5: Let F: C × D → E and G: C × D^{−} → E be functors. If

1. C is ω-complete,

2. for each D object A, F_{A} =^{def} F ( · , A): C → E has a right adjoint K_{A}: E → C, and

3. for each D object A, G_{A} =^{def} G( · , A): C → E is ω-continuous,

then Right[F, G](A) exists in C and

Right[F, G](A) = limit_{n}(K_{A} ∘ F_{A})^{n}(1) []

Example 3.5.6: As an application of this theorem, let us calculate dyn′(I, O). For this, we should take D to be C × C^{−}, E to be C × C, F: C × C × C^{−} → C × C to be

F (A, I, O) =^{def} ⟨A × I, A⟩ and G: C × C^{−} × C → C × C to be G(A, I, O) =^{def} ⟨A, O⟩.

F_{I,O} has a right adjoint H_{I,O}(D, E) =^{def} exp(I, D) × E. Therefore, dyn′(I, O) is the final T_{I,O}-coalgebra, where T_{I,O}(A) =^{def} H_{I,O}(G_{I,O}(A)) = exp(I, A)×O. Now, let us calculate

limit_{n} T_{I,O}^{n}(1).

T_{I,O}^{0}(1) ≅ 1
T_{I,O}^{1}(1) ≅ exp(I, 1) × O ≅ O ≅ exp(1, O)
T_{I,O}^{2}(1) ≅ T_{I,O}(O) ≅ exp(I, O) × O ≅ exp(1 + I, O)
T_{I,O}^{3}(1) ≅ exp(I, exp(1 + I, O)) × O
≅ exp(I × (1 + I), O) × O
≅ exp(1 + I + I^{2}, O)
⋯
T_{I,O}^{n}(1) ≅ exp(1 + I + I^{2} + ⋯ + I^{n−1}, O)
⋯

Therefore, dyn′(I, O) ≅ limit_{n} T_{I,O}^{n}(1) ≅ exp(1 + I + I^{2} + ⋯, O) ≅ exp(list(I), O). []

Computation and Categorical Data Types

In chapter 2 section 2.4, we introduced CSL expressions Exp(Γ, Δ, Ψ) which denote polymorphic functions in CSL structures. In this chapter, we will see them as programs and see how they can be executed. One of the ways to treat specifications as programs is to regard equations as rewrite rules, but in our case, CSL statements are in general conditional equations and, therefore, it is quite difficult to treat them as rewrite rules. Furthermore general rewriting cannot be regarded as real computation unless rules are Church-Rosser, otherwise, rewriting is more close to theorem proving.

There is no other way so long as we are dealing with CSL specifications. Remember that CSL was introduced in order to give semantics to categorical data types we have investigated in chapter 3. In CDT theory, we are not dealing with arbitrary CSL specifications, but some special ones, ones which are associated with CDT declarations. Therefore, we have much more hope for executing these special CSL specifications than arbitrary ones. For example, cartesian closed categories are, as is well-known, connected to lambda calculus which is a model of computation, so we can put some evaluation mechanism into them. [Curien 86], for example, has developed such a system. A difference of our approach from his is that we do not restrict ourselves only to cartesian closed categories. One of the main aims of CDT is to study categories formed by programming languages, and we should not presume any structure in the categories without proper reasons. We can only accept the cartesian closed structure in CDT if this is necessary for putting the concept of computation to it. As we will see later in this chapter, our categories are cartesian closed (with some extra structure), and by then we should know why the cartesian closed structure is necessary.

CSL expressions in section 2.4 and the CDT declaration mechanism in chapter 3 give us the basis of Categorical Programming Language (CPL) to which we will devote this chapter. CPL tries to extract the computable part of CDT. As we have seen in subsection 3.3.8, CDT in general allows us to define very strange objects which have no concept of being computable. We are going to put restrictions to the form of CDT declarations in CPL.

Therefore, in CPL, we can declare data types by CDT (with restrictions). As we have seen in section 3.4, this will determine a CSL in which we can have CSL expressions introduced in section 2.4. CSL expressions are the programs in CPL. There is no difference between programs and data. From the categorical point of view, there is nothing inside objects, that is, there are no data inside data types. CSL expressions whose domain is the terminal object are called CPL elements. The execution in CPL is essentially a reduction of a CPL element to a canonical irreducible CPL element.

Following the result of this chapter, CPL will not only exist on paper, but also can be implemented. This will be presented in chapter 5.

In section 4.1 we introduce a restriction to objects we can declare in CPL and a set of reduction rules for CPL computation. In section 4.2 we see an example of computation in CPL. In section 4.3 we prove that any computation in CPL terminates (i.e. the reductions are normalizing) by Tait’s computability method. In section 4.4 we show some properties about objects in CPL and, finally, section 4.5 gives another set of reduction rules for CPL computation which reduces CPL elements into intuitively more canonical elements.

4.1 Reduction Rules for Categorical Programming Language

In this section, we will present some basic definitions together with the reduction rules for CPL. Let us assume in the following discussion that we have defined categorical data types by a sequence of CDT declarations, D_{1}, …, D_{l}, and that we have obtained the corresponding CSL, ⟨Γ, Δ, Ψ, Θ⟩ as in definition 3.4.3.

In ordinary programming languages, we distinguish programs and data. We feed data into a program; it processes the data and then outputs the result data. We cannot feed a program into another program and data cannot process other data or programs. However, it is true that data are a special kind of programs, very simple ones. We can write data directly into programs as initialization statements or as assignments. For example, natural numbers like 1, 132, 59, etc. are data as well as constants in programs. In some languages like LISP, there is no difference between data and programs at all. CPL is not as liberated as LISP, but both data and programs are morphisms and data are just special morphisms having a special domain object.

As we know, category theory deals with the external structure of objects rather than their inner structure so it is not proper to think about data inside objects. However, we do sometimes need something similar to elements in set theory. We say elements in category theory are morphisms whose domain is the terminal object.

1 ⟶^{e} A

We say e is an element of A. If we think in the category of sets (Set), ‘1’ is the onepoint set and a morphism from the one-point set to a set corresponds to an element in the set.

Hom_{Set}(1, A) ≅ A

Hence, the definition of elements in CPL is:

Definition 4.1.1: Given a CSL signature ⟨Γ, Δ, Ψ⟩, a CPL element e is a CSL expression with no morphism variables whose domain type is the terminal object.

ρ ⊢ e: λ(X_{1}, …, X_{n}).1 → K

(see section 2.4 for typing). In case n = 0 which is very often the case, we may write ⊢ e: 1 → E where E is a functorial expression without variables. We also say that e is an element of E. []

In order for this definition to be sensible, we need to have the terminal object in our category. For simplicity, we assume that D_{1} is the CDT declaration of the terminal object as is presented in subsection 3.3.1.

Though this definition is a natural way of defining elements in category theory, it introduces non-symmetry in CPL. Remember that CDT is meant to be symmetric: e.g. if we have an object of natural numbers, we should have its dual, an object of co-natural numbers, and so on. Since we treat ‘1’ as a special object and the elements in CPL are defined in this way, we destroy the beauty of symmetry. We will see the consequence of this shortly.

Example 4.1.2: Assume that we have defined all the objects in section 3.3. Then

succ ∘ zero, pi2 ∘ pair(succ ∘ zero, nil), eval ∘ prod(pr(curry(pi2), curry(succ ∘ eval)), I) ∘ pair(succ ∘ succ ∘ zero, succ ∘ zero)

are all CPL elements. []

As we can see from this example, we cannot regard all the elements as data. ‘succ∘zero’ and ‘pair(succ ∘ zero, nil)’ can be data, but ‘pi1 ∘ pair(succ ∘ zero, nil)’ cannot be. We call special data-like CPL elements canonical CPL elements. The definition is:

Definition 4.1.3: A canonical CPL element is a CPL element which wholly consists of natural transformations introduced by left objects and factorizers by right objects. Formally, a canonical CPL element, c ∈ CE, is defined by

c : : = I | α_{L} ∘ c | ψ_{R}(e_{1}, …, e_{n}) ∘ c

where α_{L} is a natural transformation of a left object and ψ_{R} is a factorizer of a right object. Note we often do not write I at the tail of canonical elements. []

From this definition, ‘pair’ and ‘curry’ can form canonical elements, but ‘pi1’, ‘pi2’ or ‘eval’ cannot. So for the right objects, factorizers are the means of creating canonical elements. On the other hand, ‘zero’, ‘succ’ and ‘cons’ can form canonical elements, but not ‘pr’ or ‘case’. So for the left objects, natural transformations are the means of creating canonical elements.

Canonical  Non-Canonical

left object natural transformations e.g. zero, succ, nil, cons

factorizers e.g. case, pr, prl

right object

factorzers e.g. pair, curry natural transformations e.g. pi1, pi2, eval

Definition 4.1.3 is beautifully symmetrical as we hoped from the symmetry of CDT. In addition, if we look at the canonical elements in other programming languages, we note that ‘pair’ corresponds to making pairs of data, ‘curry’ corresponds to lambda abstraction and both create canonical things (i.e. we cannot process them any more as themselves), and also we note that ‘pr’ and ‘case’ are programming constructs corresponding to primitive recursive definitions and case statements and they can never be data. Therefore, definition 4.1.3 fits well with the usual notion of data.

Of course, this is not the only definition of canonical elements. It defines quite lazy canonical elements. It does not care what are inside factorizers. For example,

pair(pi1 ∘ pair(succ ∘ zero, nil), zero)

is a canonical element of ‘prod(nat, nat)’ from this definition. Some might not want to call it canonical because it is equal to another canonical element

pair(succ ∘ zero, zero)

which looks more canonical. However, this is because ‘prod’ is a rather special object. In general, expressions inside factorizers may not be elements, so we cannot demand them to be canonical (or we have to treat product-like objects special). One might still accept this easily since canonical elements in Martin-Löf’s type theory are similar to ours, but another queer aspect of our definition is that we accept

pair(pi2, pi1) ∘ pair(succ, I) ∘ zero

as a canonical element. It is equal to the following element

pair(pi2 ∘ pair(succ, I) ∘ zero, pi1 ∘ pair(succ, I) ∘ zero),

but this is again because of the special property of ‘prod’. In general

ψ_{R}(e_{1}, …, e_{n}) ∘ c

is not equal to something in the form of ψ_{R}(e′_{1}, …, e′_{n}). For example, we cannot always find other simpler canonical elements which is equal to ‘fold(f, g) ∘ c’ (where ‘fold’ is the factorizer of ‘inflist’).

There are many views of computation, but in CPL computation is the reduction of an element to a canonical element equal to the given element.

e ⇒ c

Since the reduction is not straightforward, we want to do step-by-step reduction. Therefore, we modify the above form of reduction to the following one.

⟨e, c⟩ ⇒ c′

This means that a CSL expression e applied to a CPL canonical element c is reduced to a CPL canonical element c′. It is like calculating the result of applying an element c to a function e. Obviously, e ∘ c should be semantically equal to c′. Since a CPL element is a morphism from the terminal object and ‘I’ is its canonical element, if we want to reduce an arbitrary CPL element e we can ask for the following reduction.

⟨e, I⟩ ⇒ c

In the following, we assume that the associativity of ‘∘’ (the composition of morphisms) has been taken care by some means so that in our rules we do not consider it. We also assume that there are no functors in CPL elements because we can always replace them with factorizers and natural transformations. For example,

eval ∘ prod(curry(succ), nil)

is equivalent to eval ∘ pair(curry(succ) ∘ pi1, nil ∘ pi2).

Let us now define rules for the reductions. The simplest one is for identities. Since I∘c is equal to c, we should have the following rule.

⟨I, c⟩ ⇒ c  (IDENT)

Next, for the composition, we naturally have

\frac{⟨e_{2}, c⟩ ⇒ c′′ ⟨e_{1}, c′′⟩ ⇒ c′}{⟨e_{1} ∘ e_{2}, c⟩ ⇒ c′}  (COMP)

In case that e is a natural transformation introduced by a left object or a factorizer introduced by a right object, the rule is easy because the composition of e with a canonical element is canonical by definition 4.1.3.

⟨α_{L}, c⟩ ⇒ α_{L} ∘ c  (L-NAT)
⟨ψ_{R}(e_{1}, …, e_{n}), c⟩ ⇒ ψ_{R}(e_{1}, …, e_{n}) ∘ c  (R-FACT)

For example, ⟨succ, zero⟩ ⇒ succ ∘ zero and

⟨curry(pi2), pair(zero, succ ∘ zero)⟩ ⇒ curry(pi2) ∘ pair(zero, succ ∘ zero).

Difficulty comes in for the other cases, i.e. when e is a natural transformation of a right object or a factorizer of a left object. Let us first consider the case for a factorizer ψ_{L} introduced by the following left object.

left object L(X) with ψ_{L} is

α_{L}: E(L, X) → E′(L, X) end object From the property of this object, we have a CSL equation

E′(ψ_{L}(e), I) ∘ α_{L} = e ∘ E(ψ_{L}(e), I).

An instance of this equation is ‘pr(f, g)∘succ = g ∘pr(f, g)’, and in this case we should have a rewrite rule from ‘pr(f, g)∘succ’ to ‘g ∘pr(f, g)’. Therefore, in general we might have the following rule.

\frac{⟨e ∘ E(ψ_{L}(e), I), c⟩ ⇒ c′}{⟨E′(ψ_{L}(e), I), α_{L} ∘ c⟩ ⇒ c′}

However, this rule is not what we wanted. We wanted a rule for ⟨ψ_{L}(e), c′′⟩ ⇒ c′′′. In order that the above rule to be a one we want, E′(L, X) should be simply L, and we get

\frac{⟨e ∘ E(ψ_{L}(e), I), c⟩ ⇒ c′}{⟨ψ_{L}(e), α_{L} ∘ c⟩ ⇒ c′} .  (L-FACT)

The restriction that demands E′(L, X) should be L is the first restriction we put onto objects in order to obtain the CPL computation rules. The left objects introduced in chapter 3, initial object, coproducts, natural number object and lists, all satisfy this restriction except the left adjoint functor of ‘list’ which we do not expect to be in the world of computation. If E′(L, X) is something other than L, we are allowing to have the left adjoint L′ of E′( · , X) by

left object L′(X, Y) with ψ_{L′} is

α_{L′}: Y → E′(LL′, X)

end object.

In familiar categories (e.g. the category of sets), a functor F: C → C hardly has a left adjoint: e.g. the product functor • × A does not have one, nor does the coproduct functor • + A.

As an example of L-FACT, let us write the rules for the factorizer associated with the natural number object. There are two rules for two natural transformations, ‘zero’ and ‘succ’.

\frac{⟨e, c⟩ ⇒ c′}{⟨pr(e, e′), zero ∘ c⟩ ⇒ c′}  \frac{⟨e′ ∘ pr(e, e′), c⟩ ⇒ c′}{⟨pr(e, e′), succ ∘ c⟩ ⇒ c′}

Let us now consider the last case, the case for the reduction rule of a natural transformation α_{R} introduced by the following right object declaration.

right object R(X) with ψ_{R} is α_{R}: E(R, X) → E′(R, X)

end object

From the property of this object, we have a CSL equation

α_{R} ∘ E(ψ_{R}(e), I) = E′(ψ_{R}(e), I) ∘ e.

An instance of this equation is ‘pi1 ∘ pair(f, g) = f’, and in this case we should have a rule to rewrite ‘pi1 ∘ pair(f, g)’ to ‘f’. Therefore, in general we have a rule rewriting from the left-hand side to the right-hand side as the following rule.

\frac{⟨E′(ψ_{R}(e), I) ∘ e, c⟩ ⇒ c′}{⟨α_{R}, E(ψ_{R}(e), I) ∘ c⟩ ⇒ c′}

However, this rule is not quite right because E(ψ_{R}(e), I) ∘ c is not a canonical element. We cannot have functors in canonical elements. Therefore, what the rule should really look like is

\frac{c = E(ψ_{R}(e), I) ∘ c′′ ⟨E′(ψ_{R}(e), I) ∘ e, c′′⟩ ⇒ c′}{⟨α_{R}, c⟩ ⇒ c′} .  (+)

We now have a different problem of finding out an expression e and a canonical element c′′ from a given canonical element c such that

c = E(ψ_{R}(e), I) ∘ c′′.

Since we are dealing with computation, we need a mechanical way of solving this problem. Let us introduce another form of reduction rules.

⟨c, E, R⟩ ⇝ ⟨ψ_{R}(e), c′′⟩  (∗)

such that c = E(ψ_{R}(e), I)∘c′′ where E is a functorial expression in which R is a variable. By these rules, we can rewrite the rule (+) to

\frac{⟨c, E(R, X), R⟩ ⇝ ⟨ψ_{R}(e), c′′⟩ ⟨E′(ψ_{R}(e), I) ∘ e, c′′⟩ ⇒ c′}{⟨α_{R}, c⟩ ⇒ c′} .  (R-NAT)

We now have to list the rules for (∗). If E is simply R itself, c should be E(ψ_{R}(e), I) ∘ c′′ = ψ_{R}(e) ∘ c′′. Therefore, the rule should be

⟨ψ_{R}(e) ∘ c′′, R, R⟩ ⇝ ⟨ψ_{R}(e), c′′⟩.  (R-NAT-V)

Next, if E(R, X) does not depend on R, c is E(ψ_{R}(e), I) ∘ c′′ = c′′, so the rule may be

⟨c, E, R⟩ ⇝ ⟨ψ_{R}(e), c⟩,

but where does ψ_{R}(e) come from? We cannot determine e. Therefore, E(R, X) must not be independent from R (i.e. E(R, X) should not be free of R).

The case left is when E(R, X) is not a variable but a real functorial expression. Let it be

F (Ê_{1}(R, X), …, Ê_{n}(R, X)),  (1)

where F is a functor name. In this case, the equation we are solving is

c = F (Ê_{1}(ψ_{R}(e), I), …, Ê_{n}(ψ_{R}(e), I)) ∘ c′′.  (2)

Since functors are always represented by their associated factorizers, the equation looks like

c = ψ_{F} (⋯ ∘ Ê_{1}(ψ_{R}(e), I) ∘ ⋯ ∘ Ê_{n}(ψ_{R}(e), I) ∘ ⋯) ∘ c′′.  (3)

As we can see, we might have to pick up the same ψ_{R}(e) from more than one place and this would be a trouble. Because ψ_{R}(e) is a general CSL expression and we cannot do theorem proving to show two CSL expressions are equal when doing the CPL computation. Therefore, we need to restrict that ψ_{R}(e) should appear only once in (3). In order for this, we have to first restrict that only one Ê_{i} in (2) contains R. Without loss of generality, we can assume it is Ê_{1}(R, X), and since we are only interested in the first argument of F, we assume that F is a unary functor and E(R, X) is F (Ê(R, X)). Now (2) looks like

c = F (Ê(ψ_{R}(e), I)) ∘ c′′,  (2′)

but still (3) might have more than one ψ_{R}(e) because when we expand functors by factorizers using (LFEQ) or (RFEQ) in definition 3.4.1, we might duplicate ψ_{R}(e). Before stating the restriction to guarantee the no-duplication of ψ_{R}(e), let us note that F should be a functor introduced by a right object declaration. This is because, if we look at the equation (3), c is a canonical element consisting of left natural transformations and right factorizers, so ψ_{F} should be a right factorizer. Let the following be the declaration of F.

right object F (Y) with ψ_{F} is β_{1}: Ẽ_{1}(F, Y) → Ẽ′_{1}(F, Y)

⋯

β_{m}: Ẽ_{m}(F, Y) → Ẽ′_{m}(F, Y) end object

(4)

From the equation (RFEQ) in definition 3.4.1, (3) really is

c = ψ_{F} ( Ẽ′_{1}(I, Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ Ẽ_{1}(I, Ê(ψ_{R}(e), I)),
⋯
Ẽ′_{m}(I, Ê(ψ_{R}(e), I)) ∘ β_{m} ∘ Ẽ_{m}(I, Ê(ψ_{R}(e), I)) ) ∘ c′′

(3′)

In order that ψ_{R}(e) should appear only once in this equation, Y should appear only once in one of Ẽ_{i} and Ẽ′_{i}. In order to show that Y should not be in one of Ẽ′_{i}, let F be simply

right object F (Y) with ψ_{F} is

β: Y → F end object.

(4′)

(3) becomes

c = ψ_{F} (β ∘ Ê(ψ_{R}(e), I)) ∘ c′′.

We may demand that c should be ψ_{F} (ê) ∘ ĉ and find ψ_{R}(e) such that

ê = β ∘ Ê(ψ_{R}(e), I),

but how can we solve this equation? In general, we need theorem proving for this. We should have reduced the problem recursively into

⟨č, Ě, R⟩ ⇝ ⟨ψ_{R}(e), č⟩,

but there is no way to do this if Y appears in one of Ẽ_{i}, because ê should never be an element. The typing rule in definition 3.2.2 gives us

\frac{ê: Y → Z}{ψ_{F} (ê): Z → F (Y)}

and we cannot choose Y to be the terminal object. If Y and F were the other way round in (4′), we could choose Z to be the terminal object to make ê an element. Therefore, if Y is in one of Ẽ′_{i} in (4), we have a possibility of reducing the problem of solving (3′) into a smaller problem of the same kind. Without losing generality, we can assume that Y only appears in Ẽ′_{1} in (4). Now, (3′) is

c = ψ_{F} (Ẽ′_{1}(I, Ê(ψ_{R}(e), I)) ∘ β_{1}, β_{2}, …, β_{m}) ∘ c′′.  (3′′)

We demand c to be ψ_{F} (ê_{1}, ê_{2}, …, ê_{m}) ∘ ĉ, so (3′′) is further rewritten to

ψ_{F} (ê_{1}, ê_{2}, …, ê_{m}) ∘ ĉ = ψ_{F} (Ẽ′_{1}(I, Ê(ψ_{R}(e), I)) ∘ β_{1}, β_{2}, …, β_{m}) ∘ c′′.  (3′′′)

Here, we cannot jump to the conclusion that ê_{1} is Ẽ′_{1}(I, Ê(ψ_{R}(e), I)) ∘ β_{1}, ê_{2} is β_{2}, …, and ĉ is c′′, because a part of ĉ may well contribute to form Ẽ′_{1}(I, Ê(ψ_{R}(e), I)). What is desirable is that we could rewrite ψ_{F} (ê_{1}, ê_{2}, …, ê_{m}) ∘ ĉ to ψ_{F} (ê′_{1}, ê′_{2}, …, ê′_{m}) like pair(f, g) ∘ h = pair(f ∘ h, g ∘ h). This is possible when each Ẽ′_{i} in (4) does not depend on F.

Proposition 4.1.4: Let R be a right object defined by

right object R(X_{1}, …, X_{n}) with ψ_{R} is

α_{1}: E_{1}(R, X_{1}, …, X_{n}) → E′_{1}(X_{1}, …, X_{n})
⋯
α_{m}: E_{m}(R, X_{1}, …, X_{n}) → E′_{m}(X_{1}, …, X_{n})

end object

(note that E′_{i} does not depend on R), then

ψ_{R}(e_{1}, …, e_{m}) ∘ e′ = ψ_{R}(e_{1} ∘ E_{1}(e′, I, …, I), …, e_{m} ∘ E_{m}(e′, I, …, I)) (REQC)

Proof: From (RCEQ) in definition 3.4.1,

α_{1} ∘ E_{1}(ψ_{R}(e_{1}, …, e_{m}) ∘ e′, I, …, I) = f_{1} ∧
⋯
α_{m} ∘ E_{m}(ψ_{R}(e_{1}, …, e_{m}) ∘ e′, I, …, I) = f_{m} ∧
⇒ ψ_{R}(e_{1}, …, e_{m}) ∘ e′ = ψ_{R}(f_{1}, …, f_{m}).

Using (REQ_{i}) and the fact that E_{i} is covariant in R, we get

e_{1} ∘ E_{1}(e′, I, …, I) = f_{1} ∧ … ∧ e_{m} ∘ E_{m}(e′, I, …, I) = f_{m}
⇒ ψ_{R}(e_{1}, …, e_{m}) ∘ e′ = ψ_{R}(f_{1}, …, f_{m}).

Therefore,

ψ_{R}(e_{1}, …, e_{m}) ∘ c′ = ψ_{R}(e_{1} ∘ E_{1}(e′, I, …, I), …, e_{m} ∘ E_{m}(e′, I, …, I)). []

We call this kind of right objects unconditioned. The name indicates that the objects are characterized without using conditional CSL equations. In fact, (REQ_{i}), (REQC), (RFEQ) and the following (REQI) characterize the unconditioned right objects.^{1}

ψ_{R}(α_{1}, …, α_{m}) = I  (REQI)

Therefore, we assume that in (4) F does not appear in any of Ẽ′_{i}. As we have already assumed that Y appears only in Ẽ′_{1}, (4) now looks like

right object F (Y) with ψ_{F} is β_{1}: Ẽ_{1}(F) → Ẽ′_{1}(Y)

β_{2}: Ẽ_{2}(F) → Ẽ′_{2}
⋯
β_{m}: Ẽ_{m}(F) → Ẽ′_{m}

end object

(Ẽ′_{2}, …, Ẽ′_{m} do not depend on F or Y in this case, but in general F might have parameters other than Y and they can appear in Ẽ′_{2}, …, Ẽ′_{m}), and (3) is

ψ_{F} (ê_{1} ∘ Ẽ_{1}(ĉ), ê_{2} ∘ Ẽ_{e}(ĉ), …, ê_{m} ∘ Ẽ_{m}(ĉ))

= ψ_{F} (Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ Ẽ_{1}(c′′), β_{2} ∘ Ẽ_{2}(c′′), …, β_{m} ∘ Ẽ_{m}(c′′)). (ˆ3)

If, furthermore, the first argument of ψ_{F} is an element, we can reduce the problem of solving (3) into

ê_{1} ∘ Ẽ_{1}(ĉ) = Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ Ẽ_{1}(c′′).  (5)

Since ê_{1} ∘ Ẽ_{1}(ĉ) is an element, we can ask its canonical element and it becomes almost like the original object (3) except E is replaced. Let us see the typing rule for ψ_{F} defined in definition 3.2.2.

f_{1}: Ẽ_{1}(Z) → Ẽ′_{1}(Y) …
ψ_{F} (f_{1}, …): Z → F (Y)

Since ψ_{F} in (ˆ3) is making an element, Z above should be the terminal object 1. In order that f_{1} above is also an element, Ẽ_{1}(Z) (or Ẽ_{1}(1) because Z is 1) should also the terminal object. Because Ẽ_{1}(Z) cannot be independent from Z, Ẽ_{1}(Z) should be simply Z. Therefore, (5) is

ê_{1} ∘ ĉ = Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ c′′.  (5′)

As ê_{1} ∘ ĉ is an element, we can ask its canonical element by

⟨ê_{1}, ĉ⟩ ⇒ ĉ′,  (6)

and we can also ask to solve

ĉ′ = Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ ĉ′′  (7)

1We can define unconditioned left objects as dual.

by

⟨ĉ′, Ẽ′_{1}(Ê(R, X)), R⟩ ⇝ ⟨ψ_{R}(e), ĉ′′⟩.

If we set c′′ to be

ψ_{F} (ĉ′′, ê_{2} ∘ Ê_{2}(ĉ), …, ê_{m} ∘ Ê_{m}(ĉ)),

(ˆ3) is satisfied from (REQ_{i}) in definition 3.4.1.

Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ Ẽ_{1}(c′′) = Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ Ẽ_{1}(ψ_{F} (ĉ′′, ê_{2} ∘ Ê_{2}(ĉ), …, ê_{m} ∘ Ê_{m}(ĉ))) = Ẽ′_{1}(Ê(ψ_{R}(e), I)) ∘ β_{1} ∘ ĉ′′ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .(from (REQ_{i}))

= ĉ′ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (from (7))

= ê_{1} ∘ ĉ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .(from (6))

β_{i} ∘ Ẽ_{i}(c′′) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (i = 2, …, m) = β_{i} ∘ Ẽ_{i}(ψ_{F} (ĉ′′, ê_{2} ∘ Ê_{2}(ĉ), …, ê_{m} ∘ Ê_{m}(ĉ))) = ê_{i} ∘ Ẽ_{i}(ĉ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (from (REQ_{i}))

Therefore, we got the following rule.

\begin{matrix}⟨ê_{1}, ĉ⟩ ⇒ ĉ′ ⟨ĉ′, Ẽ′_{1}(Ê(R, X)), R⟩ ⇝ ⟨ψ_{R}(e), ĉ′′⟩ \\ ⟨ψ_{F} (ê_{1}, ê_{2}, …, ê_{m}) ∘ ĉ, F (Ê(R, X)), R⟩ \\ ⇝ ⟨ψ_{R}(e), ψ_{F} (ĉ′′, ê_{2} ∘ Ẽ_{2}(ĉ), …, ê_{m} ∘ Ê_{m}(ĉ))⟩ \end{matrix}  (R-NAT-F)

As an example of the rules (R-FACT), (R-NAT), (R-NAT-V) and (R-NAT-F), let us write the rules for the exponentials. The CDT declaration of the exponentials is

right object exp(X, Y) with curry is eval: prod(exp, X) → Y

end object

as we have seen in subsection 3.3.3. The rule (R-FACT) is simply

⟨curry(e), c⟩ ⇒ curry(e) ∘ c,

and the rule (R-NAT) is

\frac{⟨c, prod(exp, X), exp⟩ ⇝ ⟨curry(e), c′′⟩ ⟨e, c′′⟩ ⇒ c′}{⟨eval, c⟩ ⇒ c′} .

The rule (R-NAT-V) is simply

⟨curry(e) ∘ c′′, exp, exp⟩ ⇝ ⟨curry(e), c′′⟩,

and, finally, the rule (R-NAT-F) is

\frac{⟨ê_{1}, ĉ⟩ ⇒ ĉ′ ⟨ĉ′, exp, exp⟩ ⇝ ⟨curry(e), ĉ′′⟩}{⟨pair(ê_{1}, ê_{2}) ∘ ĉ, prod(exp, X), exp⟩ ⇝ ⟨curry(e), pair(ĉ′′, ê_{2} ∘ ĉ)⟩} .

CHAPTER 4. COMPUTATION AND CATEGORICAL DATA TYPES 89 We may simplify the last three rules and have the next one instead.

\frac{⟨e_{1}, c⟩ ⇒ curry(e) ∘ c′′ ⟨e, pair(c′′, e_{2} ∘ c)⟩ ⇒ c′}{⟨eval, pair(e_{1}, e_{2}) ∘ c⟩ ⇒ c′}

We will see an example using these rules in the next section. In order to obtain (R-NAT-F), we have put several restrictions to the right object declaration. To state the restrictions formally, let us introduce the notion ‘productive’. Definition 4.1.5: Functorial expressions which are productive in X are generated by the following two rules.

1. X itself is a functorial expression productive in X.

2. If P (Y_{1}, …, Y_{n}) is a functor which is productive in Y_{i} and E is a functorial expression productive in X, P (E_{1}, …, E_{i−1}, E_{i}, E_{i+1}, …, E_{n}) is productive in X, where E_{1}, …, E_{i−1}, E_{i+1}, …, E_{n} are functorial expressions which do not contain X.

A functor P (Y_{1}, …, Y_{n}) is called productive in its i-th argument Y_{i} when P is declared as a right object and its declaration

right object P (Y_{1}, …, Y_{n}) with ψ_{P} is

α_{P,1}: E_{P,1}(P, Y_{1}, …, Y_{n}) → E′_{P,1}(P, Y_{1}, …, Y_{n})
⋯
α_{P,m}: E_{P,m}(P, Y_{1}, …, Y_{n}) → E′_{P,m}(P, Y_{1}, …, Y_{n})

end object

satisfies 1. P is unconditioned (i.e. P does not appear in E′_{P,1}, …, E′_{P,m}),

2. Y_{i} does not appear in E_{P,1}, …, E_{P,m},

3. Y_{i} appears only one of E′_{P,1}, …, E′_{P,m}, so let us assume that it appears in E′_{P,j} only,

4. E_{P,j} is simply P, and

5. E′_{P,j} is a functorial expression productive in Y_{i}. Therefore, the declaration above may look more like

right object P (Y_{1}, …, Y_{i}, …, Y_{n}) with ψ_{P} is

α_{P,1}: E_{P,1}(P, Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) →
E′_{P,1}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})
⋯
α_{P,j}: P → E′_{P,j}(Y_{1}, …, Y_{i−1}, Y_{i}, Y_{i+1}, …, Y_{n})
⋯
α_{P,m}: E_{P,m}(P, Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) →
E′_{P,m}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})

end object (P) α_{P,j} may be called projection to Y_{i}. []

The functor ‘prod’ is a typical productive functor. It is productive in its both arguments. The functor ‘exp’ is not productive in any of its arguments. A functorial expression ‘prod(prod(X, exp(Y, Z)), prod(X, U))’ is productive in U but not in X or Y or Z.

Definition 4.1.6: A right object R is called computable if its declaration

right object R(X_{1}, …, X_{n}) with ψ_{R} is

α_{R,1}: E_{R,1}(R, X_{1}, …, X_{n}) → E′_{R,1}(R, X_{1}, …, X_{n})
⋯
α_{R,m}: E_{R,m}(R, X_{1}, …, X_{n}) → E′_{R,m}(R, X_{1}, …, X_{n})

end object

(RC)

satisfies that E_{R,1}, …, E_{R,m} are functorial expressions productive in R. We also call a left object L computable when its declaration is

left object L(X_{1}, …, X_{n}) with ψ_{L} is

α_{L,1}: E_{L,1}(L, X_{1}, …, X_{n}) → L
⋯
α_{L,m}: E_{L,m}(L, X_{1}, …, X_{n}) → L

end object

(LC)

[]

The reduction rules we have defined in this section work when all the objects we define are computable, and all the objects declared in section 3.3 are computable except the obscure ones in subsection 3.3.8. Obviously, we did not want to have those obscure objects in our datatype system and the computability constraint gets rid of them. In other words, the categories which are defined by declaring computable objects cannot be richer than cartesian closed category with recursive objects. Note that we did not make the restriction in the beginning. We had the ability to declare a lot of other objects, but it turned out that in order to be able to discuss the computability in CDT, the categories should be cartesian closed with recursive objects. This signifies the importance of cartesian closed categories in computer science yet again (e.g. the models of typed lambda calculus correspond to cartesian closed categories).

Note that not all the productive objects are computable by the definition 4.1.5, but from now on we only treat computable objects, so productive objects mean computable productive objects.

Definition 4.1.7: Let D_{1}, …, D_{l} be a sequence of CDT declarations defining only computable objects and let ⟨Γ, Δ, Ψ, Θ⟩ be the corresponding CSL theory defined by definition 3.4.3. Then, we can have computation rules for CPL elements over the CSL signature ⟨Γ, Δ, Ψ⟩. The computation rules are divided into two: those in the form of

⟨e, c⟩ ⇒ c′

where c and c′ are canonical elements and e and c can be composed (i.e. e ∘ c is an element), and those in the form of

⟨c, E, R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m}), c′⟩

where c and c′ are canonical elements, R is a right functor name, E is a functorial expression productive in R and, if c is an element of E′, E should be more general than E′.

1. IDENT

⟨I, c⟩ ⇒ c

2. COMP

\frac{⟨e_{2}, c⟩ ⇒ c′′ ⟨e_{1}, c′′⟩ ⇒ c′}{⟨e_{1} ∘ e_{2}, c⟩ ⇒ c′}

3. L-NAT

⟨α_{L,j}, c⟩ ⇒ α_{L,j} ∘ c

4. R-FACT

⟨ψ_{R}(e_{1}, …, e_{m}), c⟩ ⇒ ψ_{R}(e_{1}, …, e_{m}) ∘ c

5. L-FACT

\frac{⟨e_{j} ∘ E_{L,j}[ψ_{L}(e_{1}, …, e_{m})/L], c⟩ ⇒ c′}{⟨ψ_{L}(e_{1}, …, e_{m}), α_{L,j} ∘ c⟩ ⇒ c′}

6. R-NAT

\begin{matrix}⟨c, E_{R,j}, R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m}), c′′⟩ \\ ⟨E′_{R,j}[ψ_{R}(e_{1}, …, e_{m})/R] ∘ e_{j}, c′′⟩ ⇒ c′ \end{matrix}

⟨α_{R,j}, c⟩ ⇒ c′

7. R-NAT-V

⟨ψ_{R}(e_{1}, …, e_{m}) ∘ c′′, R, R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m}), c′′⟩

8. R-NAT-F

R ∈ E_{i} Y_{i} ∈ E′_{P,j} ⟨ê_{j}, c⟩ ⇒ c′
⟨c′, E′_{P,j}[E_{i}/Y_{i}], R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m′}), c′′⟩

⟨ψ_{P} (ê_{1}, …, ê_{m}) ∘ c, P (E_{1}, …, E_{n}), R⟩ ⇝

⟨ψ_{R}(e_{1}, …, e_{m′}), ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …,
ê_{j−1} ∘ E_{P,j−1}[c/P], c′′, ê_{j+1} ∘ E_{P,j+1}[c/P], …, ê_{m} ∘ E_{P,m}[c/P])⟩

where the objects L, R and P are defined as (LC), (RC) and (P), respectively, and R ∈ E_{i} means that R appears in a functorial expression E_{i}. []

We have to show that the rules are well-formed, but we have to show their soundness at the same time. We will do this in section 4.3 as well as showing that every reduction terminates (in other words, every element is normalizable by these rules).

4.2 An Example of using Reduction Rules

In this section, we will see an example computation in CPL using the reduction rules defined in the previous section. Since computation by hand is very tiresome, we do only one example, but we will see some more examples of CPL computation done by a computer in chapter 5.

Let us assume that we have declared the terminal object as in subsection 3.3.1, products as in subsection 3.3.2, exponentials as in subsection 3.3.3 and natural number object as in subsection 3.3.4. We can write down instances of the reduction rules in definition 4.1.7 as follows.

⟨I, c⟩ ⇒ c  (IDENT)
\frac{⟨e_{2}, c⟩ ⇒ c′′ ⟨e_{1}, c′′⟩ ⇒ c′}{⟨e_{1} ∘ e_{2}, c⟩ ⇒ c′}  (COMP)

For the terminal object, we have

⟨!, c⟩ ⇒ ! ∘ c.  (R-FACT_{!})

For products, we have

⟨pair(e_{1}, e_{2}), c⟩ ⇒ pair(e_{1}, e_{2}) ∘ c,  (R-FACT_{pair})
\frac{⟨c, R, R⟩ ⇝ ⟨pair(e_{1}, e_{2}), c′′⟩ ⟨e_{1}, c′′⟩ ⇒ c′}{⟨pi1, c⟩ ⇒ c′} ,  (R-NAT_{pi1})

and

⟨pair(e_{1}, e_{2}) ∘ c, prod, prod⟩ ⇝ ⟨pair(e_{1}, e_{2}), c⟩.  (R-NAT-V_{prod})

If we combine (R-NAT_{pi1}) and (R-NAT-V_{prod}) together, we get a familiar rule

\frac{⟨e_{1}, c⟩ ⇒ c′}{⟨pi1, pair(e_{1}, e_{2}) ∘ c⟩ ⇒ c′} .  (R-NAT′_{pi1})

Similarly, for ‘pi2’, we have

\frac{⟨e_{2}, c⟩ ⇒ c′}{⟨pi2, pair(e_{1}, e_{2}) ∘ c⟩ ⇒ c′} .  (R-NAT′_{pi2})

For exponentials, as we have seen in the previous section, we have the following two rules.

⟨curry(e), c⟩ ⇒ curry(e) ∘ c  (R-FACT_{curry})
\frac{⟨e_{1}, c⟩ ⇒ curry(e) ∘ c′′ ⟨e, pair(c′′, e_{2} ∘ c)⟩ ⇒ c′}{⟨eval, pair(e_{1}, e_{2}) ∘ c⟩ ⇒ c′}  (R-NAT′_{eval})

For natural number object, we have

⟨zero, c⟩ ⇒ zero ∘ c,  (L-NAT_{zero})
⟨succ, c⟩ ⇒ succ ∘ c,  (L-NAT_{succ})

\frac{⟨e_{1}, c⟩ ⇒ c′}{⟨pr(e_{1}, e_{2}), zero ∘ c⟩ ⇒ c′} ,  (L-FACT_{zero})

and

\frac{⟨e_{2} ∘ pr(e_{1}, e_{2}), c⟩ ⇒ c′}{⟨pr(e_{1}, e_{2}), succ ∘ c⟩ ⇒ c′} .  (L-FACT_{succ})

Now let us try to calculate ‘1 + 1’ in CPL. The addition function is defined in subsection 3.3.4 as

add = eval ∘ prod(pr(curry(pi2), curry(succ ∘ eval)), I).

If we expand ‘prod’ by ‘pair’, we get

add = eval ∘ pair(pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1, pi2).

Therefore, the calculation ‘1 + 1’ corresponds to the following reduction.

⟨eval ∘ pair(pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1, pi2), pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c

(1)

From (COMP),

⟨pair(pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1, pi2), pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c_{1} ⟨eval, c_{1}⟩ ⇒ c

⟨eval ∘ pair(pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1, pi2), pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c

From (R-FACT_{pair}), c_{1} is

pair(pr(curry(pi2, curry(succ ∘ eval) ∘ pi1, pi2) ∘ pair(succ ∘ zero, succ ∘ zero),

so we need to calculate

⟨eval, pair(pr(curry(pi2, curry(succ ∘ eval) ∘ pi1, pi2)∘ pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c.

From (R-NAT′_{eval}),

⟨pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1,

pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ curry(e_{1}) ∘ c_{2} ⟨e_{1}, pair(c_{2}, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c

⟨eval, pair(pr(curry(pi2, curry(succ ∘ eval) ∘ pi1, pi2)∘ pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c.

(2)

From (COMP),

⟨pi1, pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c_{3}

⟨pr(curry(pi2), curry(succ ∘ eval)), c_{3}⟩ ⇒ curry(e_{1}) ∘ c_{2} ⟨pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1,

pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ curry(e_{1}) ∘ c_{2} (3)

CHAPTER 4. COMPUTATION AND CATEGORICAL DATA TYPES 94 From (R-NAT′_{pi1}),

\frac{⟨succ ∘ zero,!⟩ ⇒ c_{3}}{⟨pi1, pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ c_{3}} ,

and from (L-NAT_{zero}) and (L-NAT_{succ}), c_{3} is

succ ∘ zero ∘!.

Going back to (3), we need to calculate

⟨pr(curry(pi2), curry(succ ∘ eval)), succ ∘ zero ∘!⟩ ⇒ curry(e_{1}) ∘ c_{2}.

From (L-FACT_{succ}),

⟨curry(succ ∘ eval) ∘ pr(curry(pi2), curry(succ ∘ eval)),

zero ∘!⟩ ⇒ curry(e_{1}) ∘ c_{2}

⟨pr(curry(pi2), curry(succ ∘ eval)), succ ∘ zero ∘!⟩ ⇒ curry(e_{1}) ∘ c_{2}

and from (COMP)

⟨pr(curry(pi2), curry(succ ∘ eval)), zero ∘!⟩ ⇒ c_{4} ⟨curry(succ ∘ eval), c_{4}⟩ ⇒ curry(e_{2}) ∘ c_{2}

⟨curry(succ ∘ eval) ∘ pr(curry(pi2), curry(succ ∘ eval)), zero ∘!⟩ ⇒ curry(e_{1}) ∘ c_{2}

(4)

From (L-FACT_{zero}),

\frac{⟨curry(pi2),!⟩ ⇒ c_{4}}{⟨pr(curry(pi2), curry(succ ∘ eval)), zero ∘!⟩ ⇒ c_{4}}

and from (R-FACT_{curry}), c_{4} is ‘curry(pi2) ∘!’. Going back to (4), e_{1} is ‘succ ∘ eval’ and c_{2} is curry(pi2) ∘!. Therefore, going back to (2), we now have to calculate

⟨succ ∘ eval, pair(curry(pi2) ∘!, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c. From (COMP),

⟨eval, pair(curry(pi2) ∘!,

pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c_{5}

⟨succ, c_{5}⟩ ⇒ c

⟨succ ∘ eval, pair(curry(pi2) ∘!, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c

(5)

From (R-NAT′_{eval}),

⟨curry(pi2) ∘!,!⟩ ⇒ curry(e_{2}) ∘ c_{6}
⟨e_{2}, pair(c_{6}, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c_{5}

⟨eval, pair(curry(pi2) ∘!, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c_{5} CHAPTER 4. COMPUTATION AND CATEGORICAL DATA TYPES 95 From (R-FACT_{!}) and (R-FACT_{curry}), e_{2} is ‘pi2’ and c_{6} is ‘! ∘!’, so we have

⟨pi2, pair(! ∘!, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c_{5}

From (R-NAT′_{pi2}),

\frac{⟨pi2 ∘ pair(succ ∘ zero, succ ∘ zero),!⟩ ⇒ c_{5}}{⟨pi2, pair(! ∘!, pi2 ∘ pair(succ ∘ zero, succ ∘ zero))⟩ ⇒ c_{5}}

From (COMP),

⟨pair(succ ∘ zero, succ ∘ zero),!⟩ ⇒ c_{6}
⟨pi2, c_{6}⟩ ⇒ c_{5}
⟨pi2 ∘ pair(succ ∘ zero, succ ∘ zero),!⟩ ⇒ c_{5}

From (R-FACT_{pair}), c_{6} is

pair(succ ∘ zero, succ ∘ zero) ∘!,

so we have

⟨pi2, pair(succ ∘ zero, succ ∘ zero) ∘!⟩ ⇒ c_{5}

and (R-NAT′_{pi2})

\frac{⟨succ ∘ zero,!⟩ ⇒ c_{5}}{⟨pi2, pair(succ ∘ zero, succ ∘ zero) ∘!⟩ ⇒ c_{5}}

By using (L-NAT_{zero}) and (L-NAT_{succ}), c_{5} is

succ ∘ zero ∘!.

Now, we go back to (5) and we need to calculate

⟨succ, succ ∘ zero ∘!⟩ ⇒ c,

but this is straightforward from (L-NAT_{succ}) and c is

succ ∘ succ ∘ zero ∘!.

Therefore, the reduction (1) is

⟨eval ∘ pair(pr(curry(pi2), curry(succ ∘ eval)) ∘ pi1, pi2),

pair(succ ∘ zero, succ ∘ zero)⟩ ⇒ succ ∘ succ ∘ zero ∘!

that is, we have shown ‘1 + 1’ is ‘2’ in CPL.

4.3 Well-Definedness and Normalization Theorem for Reduction Rules

In section 4.1, we discussed what is computation in CPL and obtained a set of reduction rules (definition 4.1.7). Usual questions to be asked when we get reduction rules are, firstly, whether they are well-defined or not and, secondly, whether they are normalizing or not. In this section, we will answer both questions affirmatively.

Let us assume in this section that we are working in a CSL theory ⟨Γ, Δ, Ψ, Θ⟩ which is obtained by a sequence of CDT declarations, D_{1}, …, D_{l}, each of which is a computable object declaration.

First, we prove the well-definedness of the reduction rules.

Theorem 4.3.1: Well-Definedness Theorem: Let e ∘ c be an element in ⟨Γ, Δ, Ψ⟩ and c be a canonical element. If from the rules listed in definition 4.1.7 we deduce

⟨e, c⟩ ⇒ c′,

then c′ is a canonical element and e ∘ c = c′ holds in ⟨Γ, Δ, Ψ, Θ⟩ (or in any CSL theory structure of this). Proof: We prove at the same time that for a canonical element c, a right functor R, a functorial expression E productive in R which is more general than the type of c, if the rules in definition 4.1.7 deduce

⟨c, E, R⟩ ⇝ ⟨e, c′⟩,

then e is ψ_{R}(e_{1}, …, e_{m}) for some e_{1}, …, e_{n}, c′ is a canonical element and c = E[ψ(e_{1}, …, e_{m})/R]∘ c′ holds in ⟨Γ, Δ, Ψ, Θ⟩.

The proof is done by mathematical induction on the length of reduction, so all we have to do is to check each reduction rule.

1. IDENT

⟨I, c⟩ ⇒ c

It is trivial from I ∘ c = c.

2. COMP

\frac{⟨e_{2}, c⟩ ⇒ c′′ ⟨e_{1}, c′′⟩ ⇒ c′}{⟨e_{1} ∘ e_{2}, c⟩ ⇒ c′}

From the induction hypothesis c′ is canonical and c′ = e_{1} ∘ c′′ = e_{1} ∘ e_{2} ∘ c.

3. L-NAT

⟨α_{L,j}, c⟩ ⇒ α_{L,j} ∘ c

It is trivial since α_{L,j} ∘ c is a canonical element.

4. R-FACT

⟨ψ_{R}(e_{1}, …, e_{m}), c⟩ ⇒ ψ_{R}(e_{1}, …, e_{m}) ∘ c

It is again trivial since ψ_{R}(e_{1}, …, e_{m}) ∘ c is a canonical element.

5. L-FACT

\frac{⟨e_{j} ∘ E_{L,j}[ψ_{L}(e_{1}, …, e_{m})/L], c⟩ ⇒ c′}{⟨ψ_{L}(e_{1}, …, e_{m}), α_{L,j} ∘ c⟩ ⇒ c′}

If α_{L,j} ∘ c is canonical, c is canonical, and from (LEQ_{j})

e_{j} ∘ E_{L,j}[ψ_{L}(e_{1}, …, e_{m})/L] ∘ c = ψ_{L}(e_{1}, …, e_{m}) ∘ α_{L,j} ∘ c.

Therefore, the premise of the rule is well-formed, so from the induction hypothesis c′ is canonical, and

c′ = e_{j} ∘ E_{L,j}[ψ_{L}(e_{1}, …, e_{m})/L] ∘ c = ψ_{L}(e_{1}, …, e_{m}) ∘ α_{L,j} ∘ c.

6. R-NAT

⟨c, E_{R,j}, R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m}), c′′⟩
⟨E′_{R,j}[ψ_{R}(e_{1}, …, e_{m})/R] ∘ e_{j}, c′′⟩ ⇒ c′
⟨α_{R,j}, c⟩ ⇒ c′

Since α_{R,j} can be composed with c and α_{R,j} has the type E_{R,j} → E′_{R,j}, c is an element of a functorial expression not more general than E_{R,j}. From the induction hypothesis, c′′ is a canonical element and

E_{R,j}[ψ_{R}(e_{1}, …, e_{m})/R] ∘ c′′ = c.

Therefore,

α_{R,j} ∘ c = α_{R,j} ∘ E_{R,j}[ψ_{R}(e_{1}, …, e_{m})/R] ∘ c′′ . . . . . . . . . . . . . . . . . . . . . . . . (from (REQ_{j})) = E′_{R,j}[ψ_{R}(e_{1}, …, e_{m})/R] ∘ e_{j} ∘ c′′ . . . . . . . . . . . . . . . . . . . . . . . (from hypothesis) = c. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (from hypothesis)

7. R-NAT-V

⟨ψ_{R}(e_{1}, …, e_{m}) ∘ c′′, R, R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m}), c′′⟩

R is a variable, so it is more general than anything, so the rule is well-formed. Since ψ_{R}(e_{1}, …, e_{m}) ∘ c′′ is a canonical element, so is c′′.

8. R-NAT-F

R ∈ E_{i} Y_{i} ∈ E′_{P,j} ⟨ê_{j}, c⟩ ⇒ c′
⟨c′, E′_{P,j}[E_{i}/Y_{i}], R⟩ ⇝ ⟨ψ_{R}(e_{1}, …, e_{m′}), c′′⟩

⟨ψ_{P} (ê_{1}, …, ê_{m}) ∘ c, P (E_{1}, …, E_{n}), R⟩ ⇝

⟨ψ_{R}(e_{1}, …, e_{m′}), ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …,
ê_{j−1} ∘ E_{P,j−1}[c/P], c′′, ê_{j+1} ∘ E_{P,j+1}[c/P], …, ê_{m} ∘ E_{P,m}[c/P])⟩

ψ_{P} (ê_{1}, …) ∘ c = ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …) and from the typing rule of ψ_{P}, ê_{j} ∘ E_{P,j}[c/P] = ê_{j}∘c is an element of a functorial expression which is not more general than E′_{P,j}[E_{1}/Y_{1}, …] which is not more general than E′_{P,j}[E_{i}/Y_{i}]. Therefore, the premises of the rule are well-formed and

ê_{j} ∘ E_{P,j}[c/P]

= ê_{j} ∘ c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (E_{P,j} is simply P) = c′ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (from ⟨ê_{j}, c⟩ ⇒ c′) = E′_{P,j}[E_{i}/Y_{i}][ψ_{R}(e_{1}, …)/R] ∘ c′′. . . . . . . . . . . .(from ⟨c′, E′_{P,j}[E_{i}/Y_{i}], R⟩ ⇝ …)

Therefore,

P (E_{1}, …)[ψ_{R}(e_{1}, …)/R] ∘ ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …, c′′, …)

= ψ_{P} (α_{P,1}, …, E′_{P,j}[E_{i}/Y_{i}][ψ_{R}(e_{1}, …)/R], …)

∘ ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …, c′′, …) . . . . . . . . . . . (expand P)

= ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …, E′_{P,j}[E_{i}/Y_{i}][ψ_{R}(e_{1}, …)/R] ∘ c′′, …)

. . . . . . . . . . . . . . . . . . . . . . . . . . .(from 4.1.4 and (REQ_{k}))

= ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …, ê_{j} ∘ E_{P,j}[c/P], …) . . . . . . . . . . . . . . . . . . . (from above) = ψ_{P} (ê_{1}, …, ê_{m}) ∘ c. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .(from 4.1.4)

Of course, ψ_{P} (ê_{1} ∘ E_{P,1}[c/P], …, c′′, …) is a canonical element.

We have proved the theorem as well as shown the well-formedness of the reduction rules. []

Next, we prove the normalization, that is to prove the following theorem.

Theorem 4.3.2: Normalization Theorem: For a canonical element c and a CSL expression e whose domain is compatible with the codomain of c (i.e. we can have e ∘ c as an element), there is a canonical element c′ such that

⟨e, c⟩ ⇒ c′

by the rules listed in definition 4.1.7. []

Before proving this theorem, we need some preparation. Note that the theorem proves the two things together: the existence of c′ and the reducibility of ⟨e, c⟩ ⇒ c′. Therefore, from the existence part, we will have the following corollary.

Corollary 4.3.3: For any element e in ⟨Γ, Δ, Ψ⟩, there is a canonical element c such that e = c holds in ⟨Γ, Δ, Ψ, Θ⟩. []

Showing the reducibility can be regarded as showing the termination of computation in CPL. So, every program terminates in CPL. This is what we expected because we only use primitive recursions.

First, we show a property of canonical elements.

Proposition 4.3.4: A canonical element of R(E_{1}, …, E_{n}) for a right object R defined by (RC) has the following form.

ψ_{R}(e_{1}, …, e_{m}) ∘ c

where c is another canonical element. On the other hand, a canonical element of L(E_{1}, …, E_{n}) for a left object L defined by (LC) has the following form.

α_{L,j} ∘ c

where c is another canonical element. Proof: A canonical element only consists of natural transformations of left objects and factorizers of right objects. Therefore, a canonical element should look like either

α_{L,j} ∘ c or ψ_{R}(e_{1}, …, e_{m}) ∘ c.

From the typing rules in section 2.4, the first one always gives an element of L(E_{1}, …, E_{n}) and the second one gives an element of R(E_{1}, …, E_{n}). []

From this proposition, we can see that whenever we have

⟨e, c⟩ or ⟨c, E, R⟩

we can always apply exactly one of the rules in definition 4.1.7. In other words, the computation in CPL is never stuck and deterministic. We can always proceed to the next computation step.

We are going to prove the normalization theorem by the computability method due to Tait [Tait 67]. This method is often used to show normalization of various systems especially that of lambda calculi (see, for example, [Stenlund 72] and [Lambek and Scott 86]) where two kinds of induction are used: induction on types and induction on structures. The method usually goes for lambda calculi as follows:

1. Define the notion of computable terms inductively on types.

2. Show that any computable term is normalizable.

3. Show that all the terms are computable by induction on terms.

4. Therefore, any term is normalizable.

The notion of computable terms is stronger than that of normalizable terms, but we need this stronger notion (which is a part of the essence of the Tait computability method) to carry out the normalization proof. The computability predicate also divide the two inductions involved in the proof clearly. In our case, the normalization proof goes as follows.

1. We define the notion of computable canonical elements inductively on types. Intuitively, a canonical element c is computable if

(a) α_{L} ∘ c is computable if c is computable.

(b) ψ_{R}(e) ∘ c is computable if there is a reduction ⟨α_{R}, ψ_{R}(e) ∘ c⟩ ⇒ c′ such that c′ is computable, that is all the components of ψ_{R}(e) ∘ c are computable.

2. We define the notion of calculability for expressions (we could have called it computability as well as is conventional in proofs about lambda calculi, but we distinguish them for clarity). An expression e is calculable if for any computable canonical element c there is a reduction ⟨e, c⟩ ⇒ c′ such that c′ is computable. Note that an expression e is normalizable if for any canonical element e there is a reduction ⟨e, c⟩ ⇒ c, whereas e is calculable if there is a reduction for any computable canonical element. Therefore, it should be easier to prove that an expression is calculable than to prove it is normalizable.

3. We will prove that all the expressions are calculable by structural induction.

4. As an easy corollary, we can show that any canonical element is computable.

5. Finally, we prove that all the reductions are normalizing.

First, let us assign for each n-ary functor F a function which given sets C_{1} …, C_{n} of canonical elements of type E_{1}, …, E_{n} gives a set of canonical elements C of type F (E_{1}, …, E_{n}). We write F̃ for the function (i.e. C = F̃(C_{1}, …, C_{n})). F̃ is monotonic in the ith argument if F is covariant in the ith argument, and F̃ is anti-monotonic in the ith argument if F is contravariant in the ith argument.

Definition 4.3.5: 1. For a left object^{2}

left object L(X) with ψ_{L} is α_{L}: E_{L}(L, X) → L

end object,

L̃(C) is the minimal fixed point of the following monotonic function:

S ⟼ { α_{L} ∘ c | c ∈ Ẽ_{L}(S, C) }

The minimal fixed point can be calculated as the least upper bound of the following ascending chain:

L̃_{0}(C) ⊆ L̃_{1}(C) ⊆ ⋯ ⊆ L̃_{n}(C) ⊆ L̃_{n+1}(C) ⊆ ⋯ ⊆ L̃_{ω}(C) ⊆ ⋯

where L̃_{0}(C) is ∅ and

L̃_{β+1}(C) =^{def} { α_{L} ∘ c | c ∈ Ẽ_{L}(L̃_{β}(C), C) }.

2. For a right object

right object R(X) with ψ_{R} is α_{R}: R → E′_{R}(R, X)

end object,

R̃(C) is the maximal fixed point of the following monotonic function:

S ⟼ { ψ_{R}(e) ∘ c | ⟨α_{R}, ψ_{R}(e) ∘ c⟩ ⇒ c′ such that c′ ∈ Ẽ′_{R}(S, C) }

The maximal fixed point can be calculated as the greatest lower bound of the following descending chain:

R̃_{0}(C) ⊇ R̃_{1}(C) ⊇ ⋯ ⊇ R̃_{n}(C) ⊇ R̃_{n+1}(C) ⊇ ⋯ ⊇ R̃_{ω}(C) ⊇ ⋯

where R̃_{0}(C) is the set of all the canonical elements of R(E) (where C is a set of canonical elements of type E) and

R̃_{β+1}(C) =^{def} { ψ_{R}(e) ∘ c |

⟨α_{R}, ψ_{R}(e) ∘ c⟩ ⇒ c′ such that c′ ∈ Ẽ′_{R}(R̃_{β}(C), C) }.

2For simplicity, we define this for a simple left object, but the general case should be obvious.

3. For a right object^{3}

right object R′(X) with ψ_{R′} is

α_{R′}: prod(R, E_{R′}(X)) → E′_{R′}(R′, X)

end object,

R̃′(C) is the maximal fixed point of the following monotonic function:

S ⟼ { ψ_{R′}(e) ∘ c | For any c′ ∈ Ẽ_{R′}(C) ⟨α_{R′}, pair(ψ_{R′}(e)∘c, c′)⟩ ⇒ c′′ such that c′′ ∈ Ẽ′_{R′}(S, C) }

We can similarly define R̃′_{β}(C).

Well-definedness: We have to show that F̃ is monotonic or anti-monotonic according to the variance of F. We prove this by induction on the order of declaration of objects.

1. If F is the left object L above and covariant, we show that L̃_{β} is monotonic by induction on β. L̃_{0} is trivially monotonic. L̃_{β+1}(C) is

{ α_{L} ∘ c | c ∈ Ẽ_{L}(L̃_{β}(C), C) }.

From the induction hypothesis L̃_{β} is monotonic. Since E_{L}(L, X) is covariant in both L and X, from the other induction hypothesis Ẽ_{L} is monotonic. Therefore, Ẽ_{L}(L̃_{β}(C), C) is monotonic in C, and L̃_{β+1} is monotonic. Hence, L̃ is monotonic. Similarly, we can show that L̃ is anti-monotonic if L is contravariant.

2. If F is the right object R above and covariant, we show that R̃_{β} is monotonic by induction on β. R̃_{0} is trivially monotonic. R̃_{β+1}(C) is

{ ψ_{R}(e) ∘ c | ⟨α_{R}, ψ_{R}(e) ∘ c⟩ ⇒ c′ ∧ c′ ∈ Ẽ′_{R}(R̃_{β}(C), C) }.

From the induction hypothesis, R̃_{β} is monotonic, and from the other induction hypothesis, Ẽ′_{R} is monotonic in both arguments. Therefore, R̃_{β+1} is monotonic, and by induction R̃ is monotonic. We can similarly show that R̃ is anti-monotonic if R is contravariant.

3. If F is the right object R′ above and covariant, we show that R̃′_{β} is monotonic by induction on β. R̃′_{0} is trivially monotonic. R̃′_{β+1}(C) is

{ ψ_{R′}(e) ∘ c | ∀c′ ∈ Ẽ_{R′}(C) ⟨α_{R′}, pair(ψ_{R′}(e) ∘ c, c′)⟩ ⇒ c′′ ∧
c′′ ∈ Ẽ′_{R′}(R̃′_{β}(C), C) }.

From the induction hypothesis, R̃′_{β} is monotonic, and from the other induction hypothesis, Ẽ_{R′} is anti-monotonic and Ẽ′_{R′} is monotonic in both arguments. Therefore, R̃′_{β+1} is monotonic, and by induction R̃′ is monotonic. We can similarly show that R̃′ is anti-monotonic if R′ is contravariant. [] We now define the notion of computability and calculability.

3For a right object R, since the domain of α_{R}: E_{R}(R, X) → E′_{R}(R, X) needs to be productive in R, there are basically these two cases: when E_{R}(R, X) is R and when it is prod(R, E′′(X)).

Definition 4.3.6: The set Ω_{F (E_{1},...,E_{n})} of computable canonical elements of type F (E_{1}, …, E_{n}) is defined inductively by F̃(Ω_{E_{1}}, …, Ω_{E_{n}}). []

Definition 4.3.7: An CSL expression e of type E → E′ is called calculable with respect to C → C′ for C ⊆ Ω_{E} and C′ ⊆ Ω_{E′} if for any c in C there is a reduction ⟨e, c⟩ ⇒ c′ such that c′ is in C′. When e is calculable with respect to Ω_{E} → Ω_{E′}, we simply say that e is calculable. []

Example 4.3.8: 1. For the terminal object ‘1’

right object 1 with ! end object,

since there is no natural transformation, any canonical element is computable. Let us use ⋆ to denote an arbitrary element of ˜1.

2. For the left object ‘nat’ of natural numbers

left object nat with pr is zero: 1 → nat succ: nat → nat

end object,

ñat_{0} is ∅. ñat_{1} is

{ zero ∘ c, succ ∘ c′ | c ∈ ˜1 ∧ c′ ∈ ñat_{0} } = { zero ∘ ⋆ }.

Similarly ñat_{2} consists of zero ∘ ⋆ and succ ∘ zero ∘ ⋆. In general, ñat_{n} is the set of n elements corresponding to a set of 0, 1, 2, …, and n − 1. Therefore, ñat is the set of all the canonical elements of nat.

3. For the right object ‘prod’ of products

right object prod(X, Y) with pair is pi1: prod → X pi2: prod → Y

end object,

a canonical element pair(e_{1}, e_{2}) ∘ c is computable if there are reductions

⟨pi1, pair(e_{1}, e_{2}) ∘ c⟩ ⇒ c_{1} and ⟨pi2, pair(e_{1}, e_{2}) ∘ c⟩ ⇒ c_{2}

such that c_{1} and c_{2} are computable, that is a canonical element of prod is computable if its components are computable. Since the reductions above are equivalent to ⟨e_{1}, c⟩ ⇒ c_{1} and ⟨e_{2}, c⟩ ⇒ c_{2}, if c is computable and e_{1} and e_{2} are calculable, pair(e_{1}, e_{2}) ∘ c is computable.

4. For the right object ‘exp’ of exponentials

right object exp(X, Y) with curry is eval: prod(exp, X) → Y

end object,

a canonical element curry(e) ∘ c of type exp(E, E′) is computable, if for any computable canonical element c′ of type E′ there is a reduction

⟨eval, pair(curry(e) ∘ c, c′)⟩ ⇒ c′′

and c′′ is computable. The reduction is equivalent to ⟨e, pair(c, c′)⟩ ⇒ c′′. Since pair(c, c′) is computable, there is such a reduction if e is calculable. Remember that curry(e) corresponds to the closure of e (or lambda closed term of e) so that we can say that a closure is calculable if the application with canonical elements always results canonical elements. This exactly corresponds to the definition of computability for lambda expressions (see [Stenlund 72]).

5. For the right object ‘inflist’ of infinite lists

right object inflist(X) with fold is head: inflist → X tail: inflist → inflist

end object,

let us figure out the computable canonical elements of type inflist(nat). ĩnflist_{0}(Ω_{nat}) is the set of all the canonical elements of type inflist(nat). ĩnflist_{1}(Ω_{nat}) is

\{ fold(e_{1}, e_{2}) ∘ c | \begin{matrix}⟨head, fold(e_{1}, e_{2}) ∘ c⟩ ⇒ c_{1} ∧ c_{1} ∈ Ω_{nat} ∧ \\ ⟨tail, fold(e_{1}, e_{2}) ∘ c⟩ ⇒ c_{2} ∧ c_{2} ∈ ĩnflist_{0}(Ω_{nat}) \} \end{matrix}

= { fold(e_{1}, e_{2}) ∘ c | ⟨e_{1}, c⟩ ⇒ c_{1} ∧ ⟨fold(e_{1}, e_{2}) ∘ e_{2}, c⟩ ⇒ c_{2} }.

Therefore, if e_{1} and e_{2} are calculable and c is computable, fold(e_{1}, e_{2}) ∘ c is in ĩnflist_{1}(Ω_{nat}). We can inductively show that it is in any ĩnflist_{β}(Ω_{nat}), and, therefore, it is in ĩnflist(Ω_{nat}).

6. For the left object of ordinals

left object ord with pro is ozero: 1 → ord sup: exp(nat, ord) → ord

end object,

õrd_{0} is empty, õrd_{1} is { ozero ∘ ⋆ }, and

õrd_{2}

= { sup ∘ c, ozero ∘ ⋆ | c ∈ ẽxp(ñat, õrd_{1}) }

= { sup ∘ curry(e) ∘ c, ozero ∘ ⋆ | ∀c′ ∈ ñat ⟨e, pair(c, c′)⟩ ⇒ c′′ ∧

c′′ ∈ õrd_{1} }

= { sup ∘ curry(e) ∘ c, ozero ∘ ⋆ | ∀c′ ∈ Ω_{nat} ⟨e, pair(c, c′)⟩ ⇒ ozero ∘ ⋆ }.

In general,

õrd_{β+1} = { sup ∘ curry(e) ∘ c, ozero ∘ ⋆ |
∀c′ ∈ Ω_{nat} ⟨e, pair(c, c′)⟩ ⇒ c′′ ∧ c′′ ∈ õrd_{β} }

Therefore, a canonical element sup ∘ curry(e) ∘ c is computable if the following reductions always exist:

⟨e, pair(c, c_{1})⟩ ⇒ sup ∘ curry(e_{1}) ∘ c′_{1}
⟨e_{1}, pair(c′_{1}, c_{2})⟩ ⇒ sup ∘ curry(e_{2}) ∘ c′_{2}
⟨e_{2}, pair(c′_{2}, c_{3})⟩ ⇒ sup ∘ curry(e_{3}) ∘ c′_{3}
⋯
⟨e_{β}, pair(c′_{β}, c_{β+1})⟩ ⇒ ozero ∘ ⋆ []

The next proposition intuitively means that functors preserve the structure of data. For example, when the functor ‘list’ (or map in ML and MAPCAR in LISP) is applied to a list, it only changes the components of the list and preserves the length.

Proposition 4.3.9: Let F be n-ary functor, and e_{1}, …, e_{n} be CSL expressions calculable with respect to C_{i} → C′_{i}. Then F (e_{1}, …, e_{n}) is calculable with respect to F̃(C′′_{1}, …, C′′_{n}) → F̃(C′′′_{1}, …, C′′′_{n}), where C′′_{i} is C_{i} and C′′′_{i} is C′_{i} if F is covariant in the ith argument and C′′_{i} is C′_{i} and C′′′_{i} is C_{i} if F is contravariant in the ith argument. Proof: We prove this by induction on the order of declarations of objects.

1. Let F be a left object declared by

left object L(X) with ψ_{L} is α_{L}: E_{L}(L, X) → L

end object

which is covariant in X, e be a CSL expression which is calculable with respect to C → C′. We prove that L(e) is calculable with respect to L̃_{β}(C) → L̃_{β}(C′) by induction on β. Trivially, L(e) is calculable with respect to L̃_{0}(C) → L̃_{0}(C) because L̃_{0}(C) is empty. Assume we have proved that L(e) is calculable with respect to L̃_{β}(C) → L̃_{β}(C′). An element of L̃_{β+1}(C) is α_{L} ∘ c such that c ∈ Ẽ_{L}(L̃_{β}(C), C). From L-FACT we get

\frac{⟨α_{L} ∘ E_{L}(I, e) ∘ E_{L}(L(e), I), c⟩ ⇒ c′}{⟨α_{L} ∘ E_{L}(I, e) ∘ E_{L}(ψ_{L}(α_{L} ∘ E_{L}(I, c)), I), c⟩ ⇒ c′}

\frac{⟨ψ_{L}(α_{L} ∘ E_{L}(I, e)), α_{L} ∘ c⟩ ⇒ c′}{⟨L(e), α_{L} ∘ c⟩ ⇒ α_{L} ∘ c′}

Since E_{L}(L, X) consists of functors declared before L, from the induction hypothesis, E_{L}(L(e), I) is calculable with respect to Ẽ_{L}(L̃_{β}(C), C) → Ẽ_{L}(L̃_{β}(C′), C) and E_{L}(I, e) is calculable with respect to Ẽ_{L}(L̃_{β}(C′), C) → Ẽ_{L}(L̃_{β}(C′), C′). Therefore, there is a reduction

⟨E_{L}(I, e) ∘ E_{L}(L(e), I), c⟩ ⇒ c′

such that c′ is in Ẽ_{L}(L̃_{β}(C′), C′). From definition 4.3.5, α_{L} ∘ c′ is in L̃_{β+1}(C′). Hence, L(e) is calculable with respect to L̃_{β+1}(C) → L̃_{β+1}(C′). By induction, L(e) is calculable with respect to L̃_{β}(C) → L̃_{β}(C′) for any β, and, therefore, L(e) is calculable with respect to L̃(C) → L̃(C′). When L(X) is contravariant, we can similarly prove that L(e) is calculable with respect to L̃(C′) → L̃(C).

2. Let F be a right object declared by

right object R(X) with ψ_{R} is α_{R}: R → E′_{R}(R, X)

end object

which is covariant, and e be a CSL expression which is calculable with respect to C → C′. We prove that R(e) is calculable with respect to R̃_{β}(C) → R̃_{β}(C′) by induction on β. From R-FACT, we have

⟨R(e), c⟩ ⇒ ψ_{R}(E′_{R}(I, e) ∘ α_{R}) ∘ c.

Trivially, R(e) is calculable with respect to R̃_{0}(C) → R̃_{0}(C′) because R̃_{0}(C′) is the set of all the canonical elements of R. Assume we have proved that R(e) is calculable with respect to R̃_{β}(C) → R̃_{β}(C′). An element of R̃_{β+1}(C) is ψ_{R}(e′) ∘ c′ such that there is a reduction ⟨α_{R}, ψ_{R}(e′) ∘ c′⟩ ⇒ c′′ and c′′ is in Ẽ′_{R}(R̃_{β}(C), C). We will show that the following canonical element is in R̃_{β+1}(C′):

ψ_{R}(E′_{R}(I, e) ∘ α_{R}) ∘ ψ_{R}(e′) ∘ c′  (∗)

From R-NAT, we have

\frac{⟨E′_{R}(R(e), I) ∘ E′_{R}(I, e), c′′⟩ ⇒ c′′′}{⟨E′_{R}(R(e), I) ∘ E′_{R}(I, e) ∘ α_{R}, ψ_{R}(e′) ∘ c′⟩ ⇒ c′′′}

\frac{⟨E′_{R}(ψ_{R}(E′_{R}(I, c) ∘ α_{R}), I), E′_{R}(I, e) ∘ α_{R}, ψ_{R}(e′) ∘ c′⟩ ⇒ c′′′}{⟨α_{R}, ψ_{R}(E′_{R}(I, e) ∘ α_{R}) ∘ ψ_{R}(e′) ∘ c′⟩ ⇒ c′′′}

Since E′_{R}(R, X) consists of functors declared before R, E′_{R}(R(e), I) ∘ E′_{R}(I, e) is calculable with respect to Ẽ′_{R}(R̃_{β}(C), C) → Ẽ′_{R}(R̃_{β}(C′), C′) from the induction hypothesis. Therefore, c′′′ is in Ẽ′_{R}(R̃_{β}(C′), C′), and from definition 4.3.5, (∗) is in R̃_{β+1}(C). Therefore, by induction, R(e) is calculable with respect to R̃_{β}(C) → R̃_{β}(C′) for any β, so it is calculable with respect to R̃(C) → R̃(C′). When R(X) is contravariant, we can similarly prove that R(e) is calculable with respect to R̃(C′) → R̃(C).

3. If F be a right object declared by

right object R′(X) with ψ_{R′} is

α_{R′}: prod(R′, E_{R′}(X)) → E′_{R}(R, X)

end object,

we can similarly prove that R(e) is calculable with respect to R̃(C) → R̃(C′) (or with respect to R̃(C′) → R̃(C) when R(X) is contravariant). [] In the following few lemmas, we are to prove all the expressions are calculable.

Lemma 4.3.10: I is calculable. Proof: We have to show that for any computable canonical element c there is a reduction of ⟨I, c⟩ ⇒ c′ and that c′ is computable. This is immediate from the reduction rule IDENT and that c′ is c []

Lemma 4.3.11: If both e_{1} and e_{2} are calculable, so is e_{1} ∘ e_{2}. Proof: For any computable canonical element c’ we have the following reduction from COMP:

\frac{⟨e_{2}, c⟩ ⇒ c′′ ⟨e_{1}, c′′⟩ ⇒ c′}{⟨e_{1} ∘ e_{2}, c⟩ ⇒ c′}

Since e_{2} is calculable, there is a reduction for ⟨e_{2}, c⟩ ⇒ c′′ so that c′′ is computable. Since e_{1} is calculable, there is a reduction for ⟨e_{1}, c′′⟩ ⇒ c′ so that c′ is computable. Therefore, there is a reduction for ⟨e_{1} ∘ e_{2}, c⟩ ⇒ c′ so that c′ is computable. []

Lemma 4.3.12: For any natural transformation α_{L} of a left object L, α_{L} is calculable. Proof: For any computable canonical element c, we have the following reduction by L-NAT:

⟨α_{L}, c⟩ ⇒ α_{L} ∘ c

From definition 4.3.6, α_{L} ∘ c is computable. Therefore, α_{L} is calculable. []

Lemma 4.3.13: For any natural transformation α_{R} of a right object R, α_{R} is calculable. Proof: Let R be

right object R(X) with ψ_{R} is α_{R}: R → E′_{R}(R, X)

end object,

and c be a computable canonical element R(E). For any β, c is in R̃_{β+1}(Ω_{E}). From definition 4.3.5, there exists a reduction ⟨α_{R}, c⟩ ⇒ c′ such that c′ is in Ẽ′_{R}(R̃_{β}(Ω_{E}), Ω_{E}). Because the result of reductions does not depend on β, c′ is in

Ẽ′_{R}(⋂_{β} R̃_{β}(Ω_{E}), Ω_{E}) = Ẽ′_{R}(R̃(Ω_{E}), Ω_{E}) = Ω_{E′_{R}(R(E),E)}.

Therefore, α_{R} is calculable. We can similarly prove that for a right object

right object R′(X) with ψ_{R′} is

α_{R′}: prod(R′, E_{R′}(X)) → E′_{R′}(R′, X)

end object,

α_{R′} is calculable. []

Lemma 4.3.14: If e is calculable, so is ψ_{L}(e) where L is a left object and ψ_{L} is its factorizer.

Proof: Let L be

left object L(X) with ψ_{L} is α_{L}: E_{L}(L, X) → L

end object,

and e: E_{L}(E, E′) → E be a calculable CSL expression. We will prove that ψ_{L}(e) is calculable with respect to L̃_{β}(Ω_{E′}) → Ω_{E} by induction on β. Trivially, it is calculable with respect to L̃_{0}(Ω_{E′}) → Ω_{E} because L̃_{0}(Ω_{E′}) is empty. Assume we have proved that ψ_{L}(e) is calculable with respect to L̃_{β}(Ω_{E′}) → Ω_{E}. An element in L̃_{β+1}(Ω_{E′}) is α_{L} ∘ c for c which is in Ẽ_{L}(L̃_{β}(Ω_{E′}), Ω_{E′}). From L-FACT, we get

\frac{⟨E_{L}(ψ_{L}(e), I), c⟩ ⇒ c′′ ⟨e, c′′⟩ ⇒ c′}{\frac{⟨e ∘ E_{L}(ψ_{L}(e), I), c⟩ ⇒ c′}{⟨ψ_{L}(e), α_{L} ∘ c⟩ ⇒ c′}}

From proposition 4.3.9 and the induction hypothesis, E_{L}(ψ_{L}(e), I) is calculable with respect to Ẽ_{L}(L̃_{β}(Ω_{E′}), Ω_{E′}) → Ẽ_{L}(Ω_{E}, Ω_{E′}), and there is a reduction ⟨E_{L}(ψ_{L}(e), I), c⟩ ⇒ c′′. Since e is calculable, there is a reduction ⟨e, c′′⟩ ⇒ c′ such that c′ is in Ω_{E}. Therefore, ψ_{R}(e) is calculable with respect to L̃_{β+1}(Ω_{E′}) → Ω_{E}, and by induction it is calculable with respect to L̃_{β}(Ω_{E′}) → Ω_{E} for any β. Because Ω_{L(E′)} = L̃(Ω_{E′}) is ⋃_{β} L̃_{β}(Ω_{E′}), we have proved that ψ_{L}(e) is calculable. []

Lemma 4.3.15: If e is calculable, so is ψ_{R}(e) where R is a right object and ψ_{R} is its factorizer. Proof: Let R be

right object R(X) with ψ_{R} is α_{R}: R → E′_{R}(R, X)

end object,

and e be a CSL expression of type E → E′_{R}(E, E′). We are to prove that ψ_{R}(e): E → R(E′) is calculable. Since Ω_{R(E′)} = R̃(Ω_{E′}) is ⋂_{β} R̃_{β}(Ω_{E′}), we prove that ψ_{R}(e) is calculable with respect to Ω_{E} → R̃_{β}(Ω_{E′}) by induction on β. Trivially, it is calculable with respect to Ω_{E} → R̃_{0}(Ω_{E′}) because for any c ∈ Ω_{E} we have ⟨ψ_{R}(e), c⟩ ⇒ ψ_{R}(e) ∘ c and R̃_{0}(Ω_{E′}) is the set of all the canonical elements of type R(E′). Assume we have proved that ψ_{R}(e) is calculable with respect to Ω_{E} → R̃_{β}(Ω_{E′}). For any c ∈ Ω_{E} we have ⟨ψ_{R}(e), c⟩ ⇒ ψ_{R}(e) ∘ c. From R-NAT, we get

\frac{⟨e, c⟩ ⇒ c′′ ⟨E′_{R}(ψ_{R}(e), I), c′′⟩ ⇒ c′}{⟨α_{R}, ψ_{R}(e) ∘ c⟩ ⇒ c′} .

Since e is calculable, there is a reduction ⟨e, c⟩ ⇒ c′′ and c′′ is in Ẽ′_{R}(Ω_{E}, Ω_{E′}). As we assumed that ψ_{R}(e) is calculable with respect to Ω_{E} → R̃_{β}(Ω_{E′}), E′_{R}(ψ_{R}(e), I) is calculable with respect to Ẽ′_{R}(Ω_{E}, Ω_{E′}) → Ẽ′_{R}(R̃_{β}(Ω_{E′}), Ω_{E′}) from proposition 4.3.9. Therefore, there is a reduction ⟨E′_{R}(ψ_{R}(e), I)c′′⟩ ⇒ c′ and c′ is in Ẽ′_{R}(R̃_{β}(Ω_{E′}), Ω_{E′}). From definition 4.3.5, ψ_{R}(e) ∘ c is in R̃_{β+1}(Ω_{E′}), so ψ_{R}(e) is calculable with respect to Ω_{E} → R̃_{β+1}(Ω_{E′}), and by induction it is calculable with respect to Ω_{E} → R̃_{β}(Ω_{E′}) for any β. Therefore, it is calculable with respect to Ω_{E} → R̃(Ω_{E′}). We can similarly prove that for a right object

right object R′(X) with ψ_{R′} is

α_{R′}: prod(R′, E_{R′}(X)) → E′_{R′}(R′, X)

end object,

ψ_{R′}(e) is calculable. []

Theorem 4.3.16: Any CSL expression e is calculable. Proof: This is proved by structural induction and each case follows from the lemmas, 4.3.10, 4.3.11, 4.3.12, 4.3.13, 4.3.14 and 4.3.15. []

Corollary 4.3.17: Any canonical element is computable. Proof: As a canonical element c is a CSL expression, and therefore, from theorem 4.3.16 it is calculable. Because any canonical element of the terminal object 1 is computable, specially I is computable. Therefore, there is a reduction ⟨c, I⟩ ⇒ c′ such that c′ is computable. Trivially, c′ is c (using L-NAT, R-FACT and COMP), so c is computable. []

We now finish this section by proving the normalization theorem.

Proof of Normalization 4.3.2: From theorem 4.3.16, any expression e is calculable, and from corollary 4.3.17, any canonical element is computable. Therefore, from the definition 4.3.7 of calculable expressions, there is a reduction ⟨e, c⟩ ⇒ c′. []

4.4 Properties of Computable Objects

In section 4.1, we saw that we have to restrict ourselves to computable objects (definition 4.1.6) in order to introduce our notion of computability into CDT. Let us see in this section some of the properties which these particular objects enjoy.

First, we show that computable left objects are fixed points of some domain equations.

Theorem 4.4.1: Let L be a computable left object declared as follows.

left object L(X_{1}, …, X_{n}) with ψ_{L} is

α_{L,1}: E_{L,1}(L, X_{1}, …, X_{n}) → L
⋯
α_{L,m}: E_{L,m}(L, X_{1}, …, X_{n}) → L

end object

Then, the following isomorphism holds in any CSL structure which has L and coproducts.

L(X_{1}, …, X_{n}) ≅ ∑_{j=1}^{m} E_{L,j}(L(X_{1}, …, X_{n}), X_{1}, …, X_{n})

where ∑_{j=1}^{m} is the m-ary coproduct. Furthermore, if A is an object which satisfies

A ≅ ∑_{j=1}^{m} E_{L,j}(A, X_{1}, …, X_{n}),

there is a unique morphism h from L(X_{1}, …, X_{n}) to A such that the following diagram commutes.

[figure: ∑_{j=1}^{m} E_{L,j}(A, X_{1}, …, X_{n}); ≅; A; ∑_{j=1}^{m} E_{L,j}(h, X_{1}, …, X_{n}); h; ∑_{j=1}^{m} E_{L,j}(L(X_{1}, …, X_{n}), X_{1}, …, X_{n}); ≅; L(X_{1}, …, X_{n})]

Proof: For simplicity, we prove the isomorphism in case L does not have any parameters (i.e. n = 0). Therefore, the isomorphism we prove is

L ≅ ∑_{j=1}^{m} E_{L,j}(L).

Let f be a morphism

[α_{L,1}, …, α_{L,m}]

where [ , …, ] is the factorizer of ∑_{j=1}^{m}. f is a morphism from ∑_{j=1}^{m} E_{L,j}(L) to L. Let g be a morphism

ψ_{L}(ν_{1} ∘ E_{L,1}(f), …, ν_{m} ∘ E_{L,m}(f))

where ν_{j} is the j-th injection of ∑_{j=1}^{m}. g is a morphism from L to ∑_{j=1}^{m} E_{L,j}(L). We show that f is the inverse of g. Let us first show that f ∘ g = I.

f ∘ g ∘ α_{L,j} = f ∘ ν_{j} ∘ E_{L,j}(f) ∘ E_{L,j}(g) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (from (LEQ_{j})) = α_{L,j} ∘ E_{L,j}(f) ∘ E_{L,j}(g) = α_{L,j} ∘ E_{L,j}(f ∘ g). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .(E_{L,j}(L) is covariant)

From (LCEQ),

f ∘ g = ψ_{R}(α_{L,1}, …, α_{L,m}) = I.

The second equality holds again from (LCEQ). Next we show that g ∘ f = I.

g ∘ f = [g ∘ α_{L,1}, …, g ∘ α_{L,m}] = [ν_{1} ∘ E_{L,1}(f ∘ g), …, ν_{m} ∘ E_{L,m}(f ∘ g)] = [ν_{1} ∘ E_{L,1}(I), …, ν_{m} ∘ E_{L,m}(I)] = [ν_{1}, …, ν_{m}] Therefore, L ≅ ∑_{j=1}^{m} E_{L,j}(L). For any object A which satisfies A ≅ ∑_{j=1}^{m} E_{L,j}(A), let i be the isomorphism from ∑_{j=1}^{m} E_{L,j}(A) to A, then the unique morphism is given by

ψ_{R}(i ∘ ν_{1}, …, i ∘ ν_{m}).

It is easy to see the diagram commutes from (LEQ_{j}) and the uniqueness from (LCEQ). []

If we apply this theorem to the objects we defined in chapter 3, we get the following isomorphisms.

nat ≅ 1 + nat

list(X) ≅ 1 + prod(X, list(X))

We can see the exact correspondence to domain theory. In domain theory, the domain of natural numbers and that of lists are defined as the minimal domains which satisfies the above isomorphisms.

By duality principle, we have the dual theorem of theorem 4.4.1.

Theorem 4.4.2: Let R be a computable right object declared as follows.

right object R(X_{1}, …, X_{n}) with ψ_{R} is

α_{R,1}: R → E′_{R,1}(R, X_{1}, …, X_{n})
⋯
α_{R,m}: R → E′_{R,m}(R, X_{1}, …, X_{n})

end object

Then, the following isomorphism holds in any CSL structure which has R and products.

R(X_{1}, …, X_{n}) ≅ ∏_{j=1}^{m} E′_{R,j}(R(X_{1}, …, X_{n}), X_{1}, …, X_{n})

where ∏_{j=1}^{m} is the m-ary product. Furthermore, if A is an object which satisfies

A ≅ ∏_{j=1}^{m} E′_{R,j}(A, X_{1}, …, X_{n}),

there is a unique morphism h from A to R(X_{1}, …, X_{n}) such that the following diagram commutes.

[figure: R(X_{1}, …, X_{n}); A; h; ≅; ≅; ∏_{j=1}^{m} E′_{R,j}(R(X_{1}, …, X_{n}), X_{1}, …, X_{n}); ∏_{j=1}^{m} E′_{R,j}(h, X_{1}, …, X_{n}); ∏_{j=1}^{m} E′_{R,j}(A, X_{1}, …, X_{n})]

Proof: By duality. [] We can see that the infinite list defined in subsection 3.3.6 is the maximal fixed point of the following domain equation.

inflist(X) ≅ X × inflist(X)

The next theorem states that productive objects define products.

Theorem 4.4.3: Let P (Y_{1}, …, Y_{n}) be a functor which is productive in Y_{i}. Then, there is a functor F (Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) such that

P (Y_{1}, …, Y_{n}) ≅ Y_{i} × F (Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})

Proof: First, note that it is easy to extend the theorem to productive functorial expressions by simply applying the theorem repeatedly. Let us prove the theorem by induction on the order of declaration of productive objects. Let the declaration of P to be as follows.

right object P (Y_{1}, …, Y_{i}, …, Y_{n}) with ψ_{P} is

α_{P,1}: E_{P,1}(P, Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) → E′_{P,1}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})
⋯
α_{P,j}: P → E′_{P,j}(Y_{1}, …, Y_{i−1}, Y_{i}, Y_{i+1}, …, Y_{n})
⋯
α_{P,m}: E_{P,m}(P, Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) → E′_{P,m}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})

end object

By induction hypothesis and from what we note at the beginning of the proof, there is a functor F′(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) such that

E′_{P,j}(Y_{1}, …, Y_{n}) ≅ Y_{i} × F′(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}).

Since P is a computable object as well, E_{P,k}(P, Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) is productive in P. Therefore, from induction hypothesis there are functors

G_{k}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})

such that

E_{P,k}(P, Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}) ≅ P × G_{k}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}).

Using exponentials, the above definition of P is essentially the same as

right object P (Y_{1}, …, Y_{i}, …, Y_{n}) with ψ_{P} is

α_{P,1}: P → exp(G_{1}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}),
E′_{P,1}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}))
⋯
α_{P,j}: P → Y_{i} × F′(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n})
⋯
α_{P,m}: P → exp(G_{m}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}),
E′_{P,m}(Y_{1}, …, Y_{i−1}, Y_{i+1}, …, Y_{n}))

end object From theorem 4.4.2, we have

P (Y_{1}, …, Y_{n}) ≅ Y_{i} × F′(Y_{1}, …) × ∏_{{k=1 \atop k≠j}}^{m} exp(G_{k}(Y_{1}, …), E′_{P,k}(Y_{1}, …)).

F′(Y_{1}, …)×∏m_{{k=1 \atop k≠j}} exp(G_{k}(Y_{1}, …), E′_{P,k}(Y_{1}, …)) does not depend on Y_{i}. We have proved

the theorem. []

From this theorem, we can always make the declaration of computable objects into an equivalent declaration to which we can apply theorem 4.4.2. For example, the declaration of the object for automata in subsection 3.3.7 was

right object dyn′(I, O) with univ′ is next′: prod(dyn′, I) → dyn′ output′: dyn′ → O

end object

to which we cannot apply theorem 4.4.2, but the above declaration is equivalent to the following one.

right object dyn′(I, O) with univ′ is next′: dyn′ → exp(I, dyn′) output′: dyn′ → O

end object

Then, from theorem 4.4.2 we can see dyn′(I, O) as the maximal fixed point of the following domain equation.

dyn′(I, O) ≅ exp(I, dyn′(I, O)) × O

4.5 Reduction Rules for Full Evaluation

In section 4.1 we presented a set of reduction rules which can reduce any element to a canonical element. However, the notion of canonical element (definition 4.1.3) was quite weak (or sloppy), and the canonical elements we get out of reductions sometimes not acceptable as ‘canonical’. We can define a more refined notion of canonical elements.

Definition 4.5.1: A canonical element is called uncondition, if it is generated by the following rule.

p : : = I | α_{L,j} ∘ p | ψ_{R}(e_{1}, …, e_{m}) ∘ p | ψ_{C}(…, e_{j}, …, p_{k}, …)

where R is not a unconditioned right object, C is a unconditioned object

right object C(X_{1}, …, X_{n}) with ψ_{C} is

⋯
α_{C,j}: E_{C,j}(C, X_{1}, …, X_{n}) → E′_{C,j}(X_{1}, …, X_{n})
⋯
α_{C,k}: C → E′_{C,k}(X_{1}, …, X_{n})
⋯

end object CHAPTER 4. COMPUTATION AND CATEGORICAL DATA TYPES 113 and if E_{C,k}(C, X_{1}, …, X_{n}) is simply C then the kth argument of ψ_{C} needs to be a unconditioned canonical element. [] For example,

pair(succ, I) ∘ zero and pair(pi1 ∘ pair(succ ∘ zero, nil), zero)

are canonical elements but not unconditioned. Their equivalent unconditioned canonical element is ‘pair(succ ∘ zero, zero)’. We can define reduction rules which only produce unconditioned canonical elements as result. Definition 4.5.2: The form of reduction rules is

⟨e, p⟩ ⇒ ⇒ p′

where e is a CSL expression and p is a unconditioned canonical element whose domain is compatible with the domain of e.

1. FULL-IDENT

⟨I, p⟩ ⇒ ⇒ p

2. FULL-COMP

\frac{⟨e_{2}, p⟩ ⇒ ⇒ p′′ ⟨e_{1}, p′′⟩ ⇒ ⇒ p′}{⟨e_{1} ∘ e_{2}, p⟩ ⇒ ⇒ p′}

3. FULL-L-NAT

⟨α_{L,j}, p⟩ ⇒ ⇒ α_{L,j} ∘ p

4. FULL-R-FACT

⟨ψ_{R}(e_{1}, …, e_{m}), p⟩ ⇒ ⇒ ψ_{R}(e_{1}, …, e_{m}) ∘ p

where R is not a unconditioned right object.

5. FULL-C-FACT

\frac{⟨e_{j}, p⟩ ⇒ ⇒ e′_{j} or e′_{j} ≡ e_{j} ∘ E_{C,j}[p/C]}{⟨ψ_{C}(e_{1}, …, e_{m}), p⟩ ⇒ ⇒ ψ_{C}(e′_{1}, …, e′_{m})}

where C is a unconditioned right object and e′_{j} is either the result of evaluating ⟨e_{j}, p⟩ or e_{j} ∘ E_{C,j}[p/C] depending of whether E_{C,j} is simply C or not.

6. FULL-L-FACT

\frac{⟨e_{j} ∘ E_{L,j}[ψ_{L}(e_{1}, …, e_{m})/L], p⟩ ⇒ ⇒ p′}{⟨ψ_{L}(e_{1}, …, e_{m}), α_{L,j} ∘ p⟩ ⇒ ⇒ p′}

7. FULL-R-NAT

\frac{⟨E′_{R,j}[ψ_{R}(e_{1}, …, e_{m})/R] ∘ e_{j}, ψ_{P} (…, p, …)⟩ ⇒ ⇒ p′}{⟨α_{R,j}, ψ_{P} (…, ψ_{R}(e_{1}, …, e_{m}) ∘ p, …)⟩ ⇒ ⇒ p′}

In writing down this rule, ψ_{P} (…, ψ_{R}(e_{1}, …, e_{m}) ∘ p, …) is rather inaccurate. It means picking up ψ_{R}(e_{1}, …, e_{m}) according to the occurrence of R in E_{R,j}. ψ_{P} ’s are nested as productive objects P ’s are in E_{R,j}. For example, the rule for ‘pi1’ of object ‘prod’ is

\frac{⟨p_{1}, I⟩ ⇒ ⇒ p′}{⟨pi1, pair(p_{1}, p_{2})⟩ ⇒ ⇒ p′} .

E_{prod,1} is simply ‘prod’, so there is no ψ_{C}’s. The rule for ‘eval’ of object ‘exp’ is

\frac{⟨e, pair(I, p)⟩ ⇒ ⇒ p′}{⟨eval, pair(curry(e), p)⟩ ⇒ ⇒ p′} .

Remember that E_{exp,1} is ‘prod(exp, X)’.

Let us call the new system FULL and the previous system defined in definition 4.1.7 LAZY. []

As we have proved theorem 4.3.1, we can easily show that FULL system is well-defined. In addition, we can show that the reduction in FULL system is stronger than that in LAZY system, that is,

Proposition 4.5.3: If ⟨e, p⟩ ⇒ ⇒ p′ in FULL system, then ⟨e, p⟩ ⇒ c′ in LAZY system. []

On the other hand, since a FULL reduction is nothing but the repeated application of LAZY reductions, we have the normalization theorem.

Theorem 4.5.4: For a unconditioned canonical element p and a CSL expression e whose domain is compatible with the codomain of p, there is a unconditioned canonical element p′ such that

⟨e, p⟩ ⇒ ⇒ p′

in FULL reduction system. []

Application of Categorical Data Types

In this chapter we see some applications of CDT and CPL. We have concentrated on category theory in the previous chapters and it is sometimes hard to relate our results to others if they are not familiar with category theory. The author is not claiming that it is better to use category theory in practice. Category theory is used as a guiding principle to see things without being obscured by inessentials. Therefore, once one establishes some results using category theory, it is very interesting to see what it means in other terms and we might get some deep insight.

In section 5.1, we will see an implementation of CPL. In section 5.2, we will examine the connection between CDT and typed lambda calculi and in section 5.3 we will propose a new ML which is obtained by combining the current ML and CPL.

5.1 An implementation of Categorical Programming Language

In chapter 4, we introduced a programming language CPL and its computation rules. A CPL system has been implemented using Franz Lisp. In the section, we will demonstrate the system and see some examples of reductions which it can manage.

When the system is started, it prints the following message and waits for user commands.

      Categorical Programming Language (version 3)
      cpl>

First, we have to declare some objects because the system does not know any objects when it is started. The very first object we declare is the terminal object. We use edit command to enter its declaration.

      cpl>edit

| right object 1 with !

| end object;

      right object 1 defined
      cpl>

Note that user inputs are in italic font. We define products, exponentials and natural number object as well. The declarations are exactly the same as we presented in chapter 3 (except that to make output shorter we use ‘s’ for successor and ‘0’ for zero).

      cpl>edit

| right object prod(a,b) with pair is

| pi1: prod -> a | pi2: prod -> b | end object;

      right object prod(+,+) defined
      cpl>edit

| right object exp(a,b) with curry is

| eval: prod(exp,a) -> b

| end object;

      right object exp(-,+) defined
      cpl>edit

| left object nat with pr is

| 0: 1 -> nat | s: nat -> nat | end object;

      left object nat defined
      cpl>edit

| left object coprod(a,b) with case is

| in1: a -> coprod | in2: b -> coprod | end object;

      left object coprod(+,+) defined
      cpl>

Each time we declare an object the system remembers its factorizer and natural transformations as well as the functor associated with. In the above transaction, ‘prod(+,+)’ indicates that system recongnized ‘prod’ as a covariant functor of two arguments whereas ‘exp(-,+)’ indicates that ‘exp’ is a functor which is contravariant in the first argument and covariant in the second. The variance is calculated as we formulated in section 3.2. The system can type CSL expressions using the rules in section 2.4. For example, we can ask the type of ‘pair(pi2,eval)’.

cpl>show pair(pi2,eval)

      pair(pi2,ev)
          : prod(exp(*b,*a),*b) -> prod(*b,*a)
      cpl>

where ‘*a’ and ‘*b’ are variables for objects, or we can see them as a kind of type variables in ML; ‘pair(pi2,eval)’ is a polymorphic function in this sense.

As we have done in section 4.2, we can ask to the system to calculate ‘1+1’ using ‘simp’ command.

cpl>simp eval.pair(pr(curry(pi2),curry(s.eval)).pi1,pi2).pair(s.0,s.0)

CHAPTER 5. APPLICATION OF CATEGORICAL DATA TYPES 117

s.s.0
    :1 -> nat
cpl>

Note that the composition ‘∘’ is typed as ‘.’. The system applied reduction rules to get the following reduction:

⟨eval.pair(…).pair(s.0, s.0), I⟩ ⇒ s.s.0.

We can see how the system deduced the reduction by enabling the trace mode.

cpl>set trace on cpl>simp eval.pair(pr(curry(pi2),curry(s.eval)).pi1,pi2).pair(s.0,s.0)

0:eval.pair(pr(curry(pi2),curry(s.eval)).pi1,pi2).pair(s.0,s.0)*
1:eval.pair(pr(curry(pi2),curry(s.eval)).pi1,pi2)*pair(s.0,s.0)
2:eval*pair(pr(curry(pi2),curry(s.eval)).pi1,pi2).pair(s.0,s.0)
3[1]:pr(curry(pi2),curry(s.eval)).pi1*pair(s.0,s.0)
4[1]:pr(curry(pi2),curry(s.eval)).s.0*id
5[1]:pr(curry(pi2),curry(s.eval)).s*0
6[1]:pr(curry(pi2),curry(s.eval))*s.0
7[1]:curry(s.eval).pr(curry(pi2),curry(s.eval))*0
8[1]:curry(s.eval).curry(pi2).!*
9[1]:curry(s.eval).curry(pi2)*!
10[1]:curry(s.eval)*curry(pi2).!
11[1]:*curry(s.eval).curry(pi2).!
12:s.eval*pair(curry(pi2).!,pi2.pair(s.0,s.0))
13[1]:curry(pi2).!*
14[1]:curry(pi2)*!
15[1]:*curry(pi2).!
16:s.pi2*pair(!,pi2.pair(s.0,s.0))
17:s.pi2.pair(s.0,s.0)*id
18:s.pi2*pair(s.0,s.0)
19:s.s.0*id
20:s.s*0
21:s*s.0
22:*s.s.0
s.s.0
    :1 -> nat
cpl>

Each line has the following form:

step number [ depth of computation ]: expression

∗ canonical element

It indicates the following reduction:

⟨ expression , canonical element ⟩ ⇒ …

Step 0 denotes the reduction of

    ⟨eval.pair(pr(curry(pi2), curry(s.eval)).pi1, pi2).pair(s.0, s.0), I⟩ ⇒ . . ..  (+)

Step 1 is obtained from R-FACT rule (and R-COMP); the reduction (+) is the same as the reduction of

     ⟨eval.pair(pr(curry(pi2), curry(s.eval)).pi1, pi2), pair(s.0, s.0)⟩ ⇒ . . ..

Again from R-FACT, this reduction is the same as

     ⟨eval, pair(pr(curry(pi2), curry(s.eval)).pi1, pi2).pair(s.0, s.0)⟩ ⇒ . . ..  (++)

which is step 2. From R-NAT, we have to calculate

⟨pair(pr(curry(pi2), curry(s.eval)).pi1, pi2).pair(s.0, s.0),

prod(exp, a), exp⟩ ⇝ ⟨curry(…), …⟩.

In order to do this, from R-NAT-F we have to calculate

            ⟨pr(curry(pi2), curry(s.eval)).pi1, pair(s.0, s.0)⟩ ⇒ . . .  (†)

This reduction is carried out from step 3 to step 12 and we get

  ⟨pr(curry(pi2), curry(s.eval)).pi1, pair(s.0, s.0)⟩ ⇒ curry(s.eval).curry(pi2).!.

Note that from step 3 to 4 it did the reduction

                         ⟨pi1, pair(s.0, s.0)⟩ ⇒ s.0,

and from step 6 to 7 it used L-FACT and did the reduction

             \frac{⟨curry(s.eval).pr(curry(pi1), curry(s.eval)), 0⟩ ⇒ . . .}{⟨pr(curry(pi2), curry(s.eval)), s.0⟩ ⇒ . . .} .

Therefore, (†) is

 ⟨pr(curry(pi2), curry(s.eval)).pi1, pair(s.0, s.0)⟩ ⇒ ⟨curry(s.eval), curry(pi2).!⟩,

and from R-NAT the reduction of (++) is the same as

              ⟨s.eval, pair(curry(pi2).!, pi2.pair(s.0, s.0))⟩ ⇒ . . ..

The rest of the steps are done similarly.

It is inconvenient to write down the definition of the addition every time we want to add something. Therefore, the system has the facility to give names to morphisms. For example, we can name the addition function ‘add’ and use it as follows:

cpl>let add=eval.pair(pr(curry(pi2),curry(s.eval)).pi1,pi2)

add : prod(nat,nat) -> nat defined

cpl>simp add.pair(s.0,s.s.0)

s.s.s.0
    :1 -> nat

We can define the multiplication and factorial functions.

cpl>let mult=eval.prod(pr(curry(0.!),curry(add.pair(eval,pi2))),id)

mult : prod(nat,nat) -> nat defined

cpl>let fact=pi1.pr(pair(s.0,0),pair(mult.pair(s.pi2,pi1),s.pi2))

fact : nat -> nat defined

cpl>simp mult.pair(s.s.0,s.s.s.0)

s.s.s.s.s.s.0
    :1 -> nat

cpl>simp fact.s.s.s.s.0

s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.0.!
    :1 -> nat
cpl>

Let us next define the object for lists.

cpl>edit

| left object list(p) with prl is | nil:1->list | cons:prod(p,list)->list | end object;

left object list(+) defined
cpl>edit

| let append=eval.prod(prl(curry(pi2), | curry(cons.pair(pi1.pi1,eval.pair(pi2.pi1,pi2)))), | id);

append : prod(list(*a),list(*a)) -> list(*a) defined

cpl>let reverse=prl(nil,append.pair(pi2,cons.pair(pi1,nil.!)))

reverse : list(*a) -> list(*a) defined

cpl>let hd=prl(in2,in1.pi1)

hd : list(*a) -> coprod(*a,1) defined

cpl>let hdp=case(hd,in2)

hdp : coprod(list(*a),1) -> coprod(*a,1) defined

cpl>let tl=case(in1.pi2,in2).prl(in2,in1.pair(pi1,case(cons,nil).pi2))

tl : list(*a) -> coprod(list(*a),1) defined

cpl>let tlp=case(tl,in2)

tlp : coprod(list(*a),1) -> coprod(list(*a),1) defined

cpl>let seq=pi2.pr(pair(0,nil),pair(s.pi1,cons))

seq : nat -> list(nat) defined
cpl>

The morphism ‘seq’ returns a list of length n for a given natural number n such that the list consists of the descending sequence of natural numbers, n − 1, n − 2, …, 2, 1, 0. We can try it in the system.

cpl>simp seq.s.s.s.0

cons.pair(s.pi1,cons).pair(s.pi1,cons).pair(0,nil).!
    :1 -> list(nat)
cpl>

The result dose not look like the sequence of 2, 1 and 0, but this is because our definition of canonical element (definition 4.1.3) is weak. We can ask the system to reduce an element to unconditioned canonical elements (see definition 4.5.1) using reduction rules listed in definition 4.5.2.

cpl>simp full seq.s.s.s.0

cons.pair(s.s.0.!,cons.pair(s.0.!,cons.pair(0.!,nil.!)))
    :1 -> list(nat)
cpl>

Now, it looks more like the sequence of 2, 1, and 0. We may continue to do some more reductions about lists.

cpl>simp hd.seq.s.s.s.0

in1.s.s.0.!
    :1 -> coprod(nat,1)

cpl>simp hd.nil

in2.!
    :1 -> coprod(*a,1)

cpl>simp hdp.tl.seq.s.s.s.0

in1.s.0.!

          :1 -> coprod(nat,1)

cpl>simp full append.pair(seq.s.s.0,seq.s.s.s.0)

      cons.pair(s.0.!,cons.pair(0.!,cons.pair(s.s.0.!,cons.pair(s.0.!,cons.
          pair(0.!,nil.!)))))
          :1 -> list(nat)

cpl>simp full reverse.it

      cons.pair(0.!,cons.pair(s.0.!,cons.pair(s.s.0.!,cons.pair(0.!,cons.
          pair(s.0.!,nil.!)))))
          :1 -> list(nat)
      cpl>

where ‘it’ denotes the result of the immediately-preceding reduction.

Let us next experiment with infinite lists.

      cpl>edit

| right object inflist(a) with fold is

| head: inflist -> a | tail: inflist -> inflist | end object;

      right object inflist(+) defined

cpl>let incseq=fold(id,s).0

      incseq : 1 -> inflist(nat) defined

cpl>simp head.incseq

      0
          :1 -> nat

cpl>simp head.tail.tail.tail.incseq

      s.s.s.0
          :1 -> nat

cpl>let alt=fold(head.pi1,pair(pi2,tail.pi1))

      alt : prod(inflist(*a),inflist(*a)) -> inflist(*a)

cpl>let infseq=fold(id,id).0

      infseq : 1 -> inflist(nat)

cpl>simp head.tail.tail.alt.pair(incseq,infseq)

      s.0
          :1 -> nat
      cpl>

where ‘incseq’ is the infinite increasing sequence 0, 1, 2, 3, 4, …, and ‘infseq’ is the infinite sequence of 0s. We can merge two infinite lists by ‘alt’ which picks up elements alternatively from the two infinite lists.

5.2 Typed Lambda Calculus

In this section, we will investigate connection between CPL and typed lambda calculi. Lambda calculi were invented to mathematically formalize the notion of computation. Typed lambda calculi (first order) are an important part of lambda calculi and are studied in various ways. Usually a typed lambda calculus starts with a fixed number of ground types and allows only → as type constructors. For example, [Stenlund 72] treats natural numbers and ordinals, and [Troelstra 73] deals with one level higher ordinals. An interesting question is “What kind of types can be added to lambda calculi?” Natural numbers, ordinals, lists, . . .. We will show in this section that any data types we can define in CPL can be added into typed lambda calculi.

We are to define a typed lambda calculus. As CPL does not have any ground objects to start with, our lambda calculus does not have any ground types either. Instead it has two ways of constructing types, one corresponding to forming left objects and the other corresponding to forming right objects.

Definition 5.2.1: The syntax of our lambda calculus is given as follows.

1. An enumerable set TVar of type variables. ρ, ν, … ∈ TVar.

2. The set Type of types is defined by the following rules.

\frac{ρ ∈ TVar ρ ∈ Γ}{Γ ⊢ ρ ∈ Type}  \frac{∅ ⊢ σ ∈ Type Γ ⊢ τ ∈ Type}{Γ ⊢ σ → τ ∈ Type}

\frac{Γ ∪ \{ ρ \} ⊢ σ_{1} ∈ Type  …  Γ ∪ \{ ρ \} ⊢ σ_{n} ∈ Type}{Γ ⊢ \underline{μ}ρ.(σ_{1}, …, σ_{n}) ∈ Type}

\frac{Γ ∪ \{ ρ \} ⊢ σ_{1} ∈ Type  …  Γ ∪ \{ ρ \} ⊢ σ_{n} ∈ Type}{Γ ⊢ \overline{μ}ρ.(σ_{1}, …, σ_{n}) ∈ Type}

We use σ, τ, … for the meta-variables of Type. \underline{μ}ρ.(σ_{1}, …, σ_{n}) corresponds to left objects and \overline{μ}ρ.(σ_{1}, …, σ_{n}) corresponds to right objects.

3. An enumerable set Var of variables. x, y, z, … ∈ Var.

4. The set Term of terms and their types are defined by the following rules.

\frac{x ∈ Var x : σ ∈ Γ}{Γ ⊢ x : σ}

Γ ∪ { x : σ} ⊢ t : τ Γ ⊢ λx^{σ}.t : σ → τ

\frac{Γ ⊢ t_{1} : σ → τ Γ ⊢ t_{2} : σ}{Γ ⊢ t_{1}t_{2} : τ}

Γ ⊢ C_{\underline{μ}ρ.(σ_{1},...,σ_{n}),i} : σ_{i}[\underline{μ}ρ.(σ_{1}, …, σ_{n})/ρ] → \underline{μ}ρ.(σ_{1}, …, σ_{n})

\begin{matrix}Γ ⊢ J_{\underline{μ}ρ.(σ_{1},...,σ_{n}),τ} : (σ_{1}[τ/ρ] → τ) → … → (σ_{n}[τ/ρ] → τ) → \\ \underline{μ}ρ.(σ_{1}, …, σ_{n}) → τ \end{matrix}

Γ ⊢ D_{\overline{μ}ρ.(σ_{1},...,σ_{n}),i} : \overline{μ}ρ.(σ_{1}, …, σ_{n}) → σ_{i}[\overline{μ}ρ.(σ_{1}, …, σ_{n})/ρ]

\begin{matrix}Γ ⊢ P_{\overline{μ}ρ.(σ_{1},...,σ_{n}),τ} : (τ → σ_{1}[τ/ρ]) → … → (τ → σ_{n}[τ/ρ]) → \\ τ → \overline{μ}ρ.(σ_{1}, …, σ_{n}) \end{matrix}

C_{\underline{μ}ρ.(σ_{1},...,σ_{n}),i} is the i-th constructor of \underline{μ}ρ.(σ_{1}, …, σ_{n}) and J_{\underline{μ}ρ.(σ_{1},...,σ_{n}),τ} is the generalized iterator for it. D_{\overline{μ}ρ.(σ_{1},...,σ_{n}),i} and P_{\overline{μ}ρ.(σ_{1},...,σ_{n}),τ} are the dual pairs. [] We have the usual reduction rules α and β and two delta rules. We write a ▷ b for the term a reducing to the term b by one step reduction and write a ▷^{⋆} b for a reducing to b by some steps. The two delta rules are:

J_{\underline{μ}ρ.(σ_{1},...,σ_{n}),τ}a_{1} … a_{n}(C_{\underline{μ}ρ.(σ_{1},...,σ_{n}),i}b) ▷ a_{i}(σ_{i}[J_{\underline{μ}ρ.(σ_{1},...,σ_{n}),τ}a_{1} … a_{n}/ρ]b)

and

D_{\overline{μ}ρ.(σ_{1},...,σ_{n}),i}(P_{\overline{μ}ρ.(σ_{1},...,σ_{n}),τ}a_{1} … a_{n}b) ▷ σ_{i}[P_{\overline{μ}ρ.(σ_{1},...,σ_{n}),τ}a_{1} … a_{n}/ρ](a_{i}b)

where σ[t/ρ] is a term of type σ[τ/ρ] → σ[υ/ρ] when the type of t is τ → υ and is defined as follows.

1. If ρ does not appear in σ, then σ[t/ρ] ≡ λx^{σ}.x.

2. ρ[t/ρ] ≡ t.

3. (σ_{1} → σ_{2})[t/ρ] ≡ λx^{σ_{1}→σ_{2}[τ/ρ]}.λy^{σ_{1}}.σ_{2}[t/ρ](xy).

4. \underline{μ}ν.(σ_{1}, …, σ_{n})[t/ρ] ≡ J_{\underline{μ}ν.(σ_{1}[τ/ρ],...),\underline{μ}ν.(σ_{1}[υ/ρ],...)}a_{1} … a_{n} where a_{i} ≡ λx^{σ_{i}[τ/ρ][\underline{μ}ν.(σ_{1}[υ/ρ],...)/ν]}.C_{\underline{μ}ν.(σ_{1}[τ/ρ],...),i}(σ_{i}[\underline{μ}ν.(σ_{1}[υ/ρ], …)/ν][t/ρ]x).

5. \overline{μ}ν.(σ_{1}, …, σ_{n})[t/ρ] ≡ P_{\overline{μ}ν.(σ_{1}[υ/ρ],...),\overline{μ}ν.(σ_{1}[τ/ρ],...)}a_{1} … a_{n} where a_{i} ≡ λx^{\overline{μ}ν.(σ_{1}[τ/ρ],...)}.σ_{i}[\overline{μ}ν.(σ_{1}[τ/ρ], …)/ν][t/ρ](D_{\overline{μ}ν.(σ_{1}[τ/ρ],...),i}x).

It looks very complicated but this is the faithful translation of σ[t/ρ] as σ being a functor.

Let us see some types we can define in our lambda calculus.

Example 5.2.2: The empty type can be defined as ∅ ≡ \underline{μ}ρ.(), and one point type can be defined as 1 ≡ \overline{μ}ρ.(). We denote the element of 1 as ∗ ≡ P_{1,1→1}λx^{1}.x. []

Example 5.2.3: The product of two types, σ and τ can be defined as σ×τ ≡ \overline{μ}ρ.(σ, τ). We have two projections.

π_{1} ≡ D_{σ×τ,1} : σ × τ → σ π_{2} ≡ D_{σ×τ,2} : σ × τ → τ

If a is a term of type σ and b is a term of type τ, we can define a term ⟨a, b⟩ of type σ × τ.

⟨a, b⟩ ≡ P_{σ×τ}(λx^{1}.a)(λx^{1}.b)∗ : σ × τ

We have the following reduction.

π_{1}⟨a, b⟩ ≡ D_{σ×τ,1}(P_{σ×τ,1}(λx.a)(λx.b)∗) ▷ (λx.x)((λx.a)∗) ▷^{⋆} a

Similarly, we can show that π_{2}⟨a, b⟩ ▷^{⋆} b. []

Example 5.2.4: Dually, the coproduct of σ and τ is defined as σ + τ ≡ \underline{μ}ρ.(σ, τ). Two injections are defined as follows.

ι_{1} ≡ C_{σ+τ,1} : σ → σ + τ ι_{2} ≡ C_{σ+τ,2} : τ → σ + τ

J_{σ+τ,ν} satisfies the following reductions.

\begin{matrix}J_{σ+τ,ν}ab(ι_{1}c) ≡ J_{σ+τ,ν}ab(C_{σ+τ,1}c) ▷ a((λx.x)c) ▷ ac \\ J_{σ+τ,ν}ab(ι_{2}c) ▷^{⋆} bc [] \end{matrix}

Example 5.2.5: Let us define the natural numbers in our lambda calculus. The definition of type is

ω ≡ \underline{μ}ρ.(1, ρ).

Zero and the successor function are defined by

0 ≡ C_{ω,1}∗ : ω s ≡ C_{ω,2} : ω → ω

J gives us almost the ordinary well-known iterator but its type is

J_{ω,σ} : (1 → σ) → (σ → σ) → ω → σ.

We can define the ordinary one by this J_{ω,σ} as follows.

J̃_{σ} ≡ λx.λy.λn.J_{ω,σ}(λz.x)yn : σ → (σ → σ) → ω → σ

It satisfies the usual reductions:

J̃_{σ}ab0 ▷^{⋆} J_{ω,σ}(λz.a)b(C_{ω,1}∗) ▷ (λz.a)((λx.x)∗) ▷^{⋆} a

and

J̃_{σ}ab(sn) ▷^{⋆} J_{ω,σ}(λz.a)b(C_{ω,2}n) ▷ b(J_{ω,σ}(λz.a)bn) ≈ b(J̃_{σ}abn)

where ≈ is the equivalence relation generated by ▷^{⋆}. Using J̃_{σ}, we can define all the primitive recursive functions. For example, the addition function can be define as

add ≡ λn.λm.J̃_{ω}msn : ω → ω → ω. []

Example 5.2.6: As [Stenlund 72] and [Troelstra 73], we can define the type for ordinals by Ω ≡ \underline{μ}ρ.(1, ω → ρ). We only check whether our definition of the iterator coincides with the ordinary one.

Ω ≡ \underline{μ}ρ.(1, ω → ρ)

0_{Ω} ≡ C_{Ω,1}∗ : Ω

sup ≡ C_{Ω,2} : (ω → Ω) → ω

J_{Ω,σ} : (1 → σ) → ((ω → σ) → σ) → Ω → σ

J_{Ω,σ}(λx.a)b0_{Ω} ▷ (λx.a)((λx.x)∗) ▷^{⋆} a

J_{Ω,σ}(λx.a)b(sup t) ▷ b((ω → ρ)[J_{Ω,σ}(λx.a)b/ρ]t)

≡ b((λy.λz.J_{Ω,σ}(λx.a)b(yz))t) ▷ b(λz.J_{Ω,σ}(λx.a)b(tz)) []

Example 5.2.7: Finally, the type for finite lists can be defined by

L_{σ} ≡ \underline{μ}ρ.(1, σ × ρ)

with

\begin{matrix}nil ≡ C_{L_{σ},1}∗ : L_{σ} cons ≡ C_{L_{σ},2} : σ × L_{σ} → L_{σ} \\ J_{L_{σ},τ} : (1 → τ) → (σ × τ → τ) → L_{σ} → τ \end{matrix}

whereas the type for infinite lists can be defined by I_{σ} ≡ \overline{μ}ρ.(σ, ρ) with

head ≡ D_{I_{σ},1} : I_{σ} → σ tail ≡ D_{I_{σ},2} : I_{σ} → I_{σ}
P_{I_{σ},τ} : (τ → σ) → (τ → τ) → τ → I_{σ}
head(P_{I_{σ},τ}abc) ▷^{⋆} ac  tail(P_{I_{σ},τ}abc) ▷^{⋆} P_{I_{σ},τ}ab(bc)  []

After finishing this section, the author is communicate with [Mendler 86] where recursive types are introduced into first-order and second-order typed lambda calculi. He uses least fixed points and greatest fixed points as we do, but their recursion combinator R has a different type from ours.

M: (ρ → τ) → σ → τ
R_{σ,τ}(M[\underline{μ}ρ.σ/ρ]): \underline{μ}ρ.σ → τ

The author cannot give a clear connection between our iterator and his. In addition, he takes fixed points over a single type expression and, therefore, he needs some basic type constructors like 1 and +, whereas in our lambda calculus there are no basic type constructors.

5.3 ML and Categorical Programming Language

We might say that ML is based on (first order) typed lambda calculi as we might say that LISP is based on untyped lambda calculi. The type structure of ML depends on the version of ML we are talking about. If we are talking about the original ML developed with LCF [Gordon, Milner and Wordsworth 79], it had some base types, product, disjoint sum, integer, etc. , and had ability to introduce new types via recursively defined type equations. For example, the data type for binary trees whose leaves are integers were defined as

     absrectype btree = int + (btree # btree)
         with leaf n = absbtree(inl n)
         and node(t1,t2) = absbtree(inr(t1,t2))
         and isleaf t = isl(repbtree t)
         and leafvalue t = outl(repbtree t)
         and left t = fst(outr(repbtree t))
         and right t = snd(outr(repbtree t));;

Here, we needed the coproduct type constructor ‘+’ as a primitive. We could not do without it, whereas ‘int’ can be defined in terms of others primitives (ML has it as a primitive type just because of efficiency).

At the next evolution of ML which yielded the current Standard ML [Milner 84, Harper, MacQueen and Milner 86], we discovered that the coproduct type constructor is no longer needed as a primitive. Standard ML has a ‘datatype’ declaration mechanism by which the coproduct type constructor can be defined.

     datatype 'a + 'b = inl of 'a | inr of 'b;

A datatype declaration lists the constructors of the defining type. An element of ‘'a + 'b’ can be obtained by either applying ‘inl’ to an element of ‘'a’ or applying ‘inr’ to an element of ‘'b’. We can define the data type for binary trees in Standard ML as follows.

     datatype btree = leaf of int | node of btree * btree;

The symbol ‘|’ is just like ‘+’, but we shifted from the object level of the language to the syntax level. Note that we no longer need the separate definition of ‘leaf’ or ‘node’. We can define the other functions using case statements.

     exception btree;
     fun isleaf t = case t of
                     leaf _=> true
                   | node _=> false;
     fun leafvalue t = case t of
                        leaf n => n
                      | node _=> raise btree;
     fun left t = case t of
                   leaf _=> raise btree
                 | node(t1,t2) => t1;
     fun right t = case t of
                    leaf _=> raise btree
                  | node(t1,t2) => t2;

We got rid of the coproduct type constructor from the primitives, but Standard ML still needs the product type constructor. From a category theoretic point of view, we can sense asymmetry in the type structure of Standard ML. Let us remember that CPL (or the lambda calculus defined in section 5.2) needs neither the coproduct type constructor nor the product type constructor as a primitive. We should be able to introduce the symmetry of CPL into ML. Let us proceed to the next stage of the ML evolution and define Symmetric ML.

Primitives  Declaration Mechanism

                   ML ->, unit, #, +  abstype
           Standard ML ->, unit, *    datatype
         Symmetric ML ->           datatype, codatatype
                  CPL  left object, right object

ML Evolution

Remember that datatype declarations correspond to left object declarations. We list constructors for types. In order to get rid of the product type constructor from primitives, we should have a declaration mechanism which corresponds to the right object declaration mechanism. Its syntax is

codatatype TypeParam TypeId = Id is TypeExp & ... & Id is TypeExp;

A codatatype declaration introduces a type by listing its destructors. The product type constructor can be defined as follows.

     codatatype 'a * 'b = fst is 'a & snd is 'b;

where ‘fst : 'a * 'b -> 'a’ gives the projection function to the first component and ‘snd : 'a * 'b -> 'b’ gives the projection function to the second component. If the declaration is recursive, we do not take the initial fixed point of the type equation but the final fixed point. This is firstly because of symmetry and secondly because the initial fixed points are often trivial. Because of this, we can define infinite objects by codatatype declarations. For example, the following declaration gives us the data type for infinite lists.

     codatatype 'a inflist = head is 'a & tail is 'a inflist;

If we took the initial fixed point, we would get the empty data type.

Obviously we have destructors for co-data types because we declare them, but how can we construct data for co-data types? We had case statements for data types, so we have ‘merge’ statements as dual. Its syntax is

merge Destructor <= Exp & ... & Destructor <= Exp

For example, the function ‘pair’ which makes a pair of given two elements can be defined as follows.

     fun pair(x,y) = merge fst <= x & snd <= y;

As a more complicated example, we might define a function which combines two infinite lists together.

     fun comb(l1,l2) = merge head <= head l1
                          & tail <= comb(l2,tail l1);

It is now clear that, if elements of co-data types are just records and ‘merge’ creates records after evaluating expressions, this ‘comb’ function never terminates because it tries to sweep the entire infinite lists which cannot be done in finite time. We need lazyness in the evaluation mechanism. An element of ‘inflist’ is a record of two components but each component is a closure whose computation leads to a value. A ‘merge’ statement creates a record consisting of these records. Therefore, the declaration of ‘inflist’ is not like

     datatype 'a inflist = something of 'a * 'a inflist;

but is closer to

     datatype 'a inflist = something of (unit -> 'a) *
                                       (unit -> 'a inflist);

and ‘head’, ‘tail and ‘comb’ are like

     fun head(something(x,l)) = x();
     fun tail(something(x,l)) = l();
     fun comb(l1,l2) = something(fn () => head l1,
                                fn () => comb(l2,tail l1));

Note that, as we use pattern matching to declare functions over data types, we can also use it to declare functions over co-data types. For example, an alternative definition of ‘comb’ may be

     fun head comb(l1,_) = head l1
       & tail comb(l1,l2) = comb(l2,tail l1);

Conclusions

We have looked at a categorical approach to the theory of data types. The goal of this thesis was to develop CPL (Categorical Programming Language) which is a programming language in a categorical style and which has a categorical way of defining data types.

CSL (Categorical Specification Language) was actually developed later than CDT (Categorical Data Types) and CPL. At first, CDT was given its semantics without depending on CSL. We could have carried out the thesis without CSL, but CSL provides the syntactic materials for CDT and CPL so we would have still needed those parts. CSL is very much like an ordinary algebraic specification language, but it is not trivial in two senses: the treatment of functors and the treatment of natural transformations. Functors are very similar to functions but variances make them special and interesting. Natural transformations are essentially polymorphic functions, so if there had been a specification language for polymorphic functions, we might not have needed to struggle for developing CSL. It might be interesting to investigate what polymorphic algebraic specification languages can be.

CSL is equational. Much of category theory can be presented equationally so that CSL is good enough in this sense, but presenting categorical concepts equationally loses half of the essential meaning. For example, although the adjoint situation can be explained equationally, its essence is something more. This is why, the author believes, there are so many equivalent forms of defining the adjoint situation. Therefore, it is nice to have a specification language which can naturally express categorical concepts. Sketches [Barr and Wells 85] are more categorical than equations, so it might be an idea to use sketches in CSL.

CDT is the heart of the thesis. It was developed after the author first studied category theory and tried to express categorical definitions in algebraic specification languages. As we have seen in chapter 3, algebraic specification languages can express categorical definitions but not naturally. CDT succeeded to define some basic categorical definitions like products, coproducts, exponentials, natural numbers and so on more naturally, but it cannot define, for example, pullbacks or more complicated categorical concepts. One of the suggestions to extend CDT is to allow equations inside the CDT declarations. In this way, we may define pullbacks as follows:

right object pullback(f: A → C, g: B → C) with pbpair is π_{1}: pullback → A π_{2}: pullback → B where f ∘ π_{1} = g ∘ π_{2}

end object

The declaration should be read as follows:

1. For any morphisms f: A → C and g: B → C, pullback(f, g) is an object and it is associated with two morphisms

π_{1}: pullback(f, g) → A and π_{2}: pullback(f, g) → B

such that f ∘ π_{1} = g ∘ π_{2}.

2. For any morphisms h: D → A and k: D → B such that f ∘ h = g ∘ k, there exists a unique morphism pbpair(h, k): D → pullback(f, g) such that

π_{1} ∘ pbpair(h, k) = h and π_{2} ∘ pbpair(h, k) = k

Note that ‘pullback’ is no longer a simple functor but takes two morphisms. We can similarly define pushouts, equalizers, co-equalizers and so on. In fact, we can define any finite limit or colimit. Since limits and colimits are something to do with diagrams, it seems natural to introduce the declaration mechanism of diagrams. For example, we may have a diagram consisting of three objects and two morphisms as follows:

diagram el is objects A, B, C morphisms f: A → C, g: B → C

end diagram

Then, ‘pullback’ can be regarded as taking an ‘el’ diagram as its parameter, and it is a functor from the category of ‘el’ diagrams. This extension is becoming very much similar to the parametrization mechanism in algebraic specification languages. Diagrams correspond to so-called loose specifications, and object declarations correspond to parametrized specifications (or procedures in CLEAR’s terminology) which take a specification which matches as a parameter and return a new specification. It is very interesting to investigate the possibility of CDT with equations along this line as a first class specification language. CDT we presented in this thesis was bounded by the restriction of computability. If we introduce equations, it becomes increasingly difficult to connect them to computing. If we had ‘pullback’ in CDT, we would have to prove f ∘k = g ∘h before using pbpair(k, h). Therefore, the programming would involve some proving.

CDT and CSL are essentially one sorted systems (here sort = category), and some would like to extend them to many sorted systems. We could have extended them here, but since our main goal in this thesis was to understand data types, we were interested in only one category, the category of data types, and so CDT and CSL were single sorted. Our approach is very close to that of domain theory which mainly deals only one category, the category of domains. On the other hand, algebraic specification methods deal with many categories. Each specification is associated with a category. However, they are still related in some sense because they all are algebras over the category of sets (or some other underlying category). As we mentioned above, if we extend CDT with the diagram declarations, we will have to deal with a lot of different categories of diagrams, and it will be interesting to find out what F, G-dialgebras can give us in this context.

CPL is a functional programming language without variables. It may look like FP proposed by John Backus because FP also has no variables. However, CPL is based on category theory and it has an ability to declare data types by means of CDT. CPL does not need any primitives to start with. One of the reasons for not having variables is that category theory is abstract in the sense that objects are simply points and only their outer behaviour is concerned. However, we could have variables for morphisms. For example, we might want to have

twice(f) =^{def} f ∘ f

which takes a morphism f: A → A and returns a morphism of A → A. The current CPL system cannot handle it and we have to write it like

twice =^{def} eval ∘ pair(π_{1}, eval)

which is a morphism from exp(A, A) to exp(A, A). This definition is not self-explanatory. It is evident that we need morphism variables in CPL for easier use. Note that twice(f) can simply be a macro because definitions can never be recursive.

We proposed in chapter 5 to make CPL more like an ordinary functional programming language. It has datatype declarations as well as co-datatype declarations. It is left for the future to actually implement the language. It is interesting to see how to handle (or represent) lazy data types.

Since CPL is an applicative language and has the possibility of executing programs in parallel as well as the possibility of partial evaluation, some kind of special hardware can be invented to execute CPL programs fast.

The future plan of CDT and CPL would be to extend CDT to cope with equations and to develop a total programming environment in which users can define things categorically, reason (or prove) their properties categorically, execute some programs categorically.

Bibliography

[Arbib and Manes 75] Arbib, M. A. and Manes, E. G. (1975): Arrows, Structures, and

Functors — The Categorical Imperative —. Academic Press. [Arbib and Manes 80] Arbib, M. A. and Manes, E. G. (1980): The Greatest Fixed

Points Approach to Data Types. In proceedings of Third Workshop Meeting on Categorical and Algebraic Methods in Computer Science and System Theory, Dortmund, West Germany.

[Barr and Wells 85] Barr, M. and Wells, C. (1985): A Series of Comprehensive Studies

in Mathematics Volume 278: Toposes, Triples and Theories. Springer-Verlag. [Burstall and Goguen 77] Burstall, R. M. and Goguen, J. A. (1977): Putting Theories

Together to Make Specification. In Proceedings of 5th International Joint Conference on Artificial Intelligence. pp. 1045–1058.

[Burstall and Goguen 80] Burstall, R. M. and Goguen, J. A. (1980): The Semantics of Clear: A Specification Language. Internal Report CSR-65-80, Department of Computer Science, University of Edinburgh.

[Burstall and Goguen 81] Burstall, R. M. and Goguen, J.A. (1981): An Informal Introduction to Specifications using Clear. In The Correctness Problem in Computer Sciences, Academic Press, pp. 185–213.

[Burstall and Goguen 82] Burstall, R. M. and Goguen, J.A. (1982): Algebras, Theories and Freeness: an Introduction for Computer Scientists. Internal Report CSR-65-80, Department of Computer Science, University of Edinburgh.

[Burstall and Lampson 84] Burstall, R. M. and Lampson, B. (1984): A Kernel Language for Abstract Data Types and Modules. In Lecture Notes in Computer Science, Volume 173, pp. 1–50.

[Curien 86] Curien, P-L. (1986): Categorical Combinators, Sequential Algorithms and

Functional Programming. Research Notes in Theoretical Computer Science, Pitman. [Dybjer 83] Dybjer, P. (1983): Category-Theoretic logics and Algebras of Programs.

Ph. D. thesis, Department of Computer Sciences, Chalmers University of Technology. University of Gothenburg.

[Goguen and Burstall 83] Goguen, J. A. and Burstall, R. M. (1983): Introducing In-

stitutions. In proceedings of Logic of Programming Workshop. [Goguen and Tardo 79] Goguen, J. A. and Tardo, J. (1979): An Introduction to OBJ:

A Language for Writing and Testing Software Specifications. In Specification of Reliable Software, IEEE, pp. 170–189.

[Goguen, Thatcher and Wagner 78] Goguen, J. A., Thatcher, J. W. and Wagner, E. G. (1978): An Initial Algebra Approach to the Specification, Correctness and Implementation of Abstract Data Types. In Current Trends in Programming Methodology, prentice-Hall, pp. 80–149.

[Gordon, Milner and Wordsworth 79] Gordon, M. J., Milner, A. J. and Wordsworth,

C. P. (1979): Edinburgh LCF. Lecture Notes in Computer Science, Volume 78. [Goldblatt 79] Goldblatt, R. (1979): Topoi: The Categorical Analysis of Logic. Studies

in Logic and Foundation of Mathematics, Volume 98, North-Holand. [Harper, MacQueen and Milner 86] Harper, R., MacQueen, D. and Milner, R. (1986):

Standard ML. LFCS Report Series, ECS-LFSC-86-2. Department of Computer Science, University of Edinburgh.

[Kelly 72] Kelly, G. M. (1972): Many-Variable Functorial Calculus I. In Lecture Notes

in Mathematics, Volume 281, Springer-Verlag, pp. 66–105. [Lambek and Scott 86] Lambek, J. and Scott, P. J. (1986): Introduction to Higher-

Order Categorical Logic. Cambridge Studies in Advanced Mathematics, Volume 7. [Lawvere 63] Lawvere, F. W. (1963): Functorial Semantics of Algebraic Theories. In

Proceedings of the National Academy of Science, Volume 50, pp. 869–872. [Lehmann and Smyth 81] Lehmann, D. and Smyth, M. (1981): Algebraic Specification

of Data Types – A Synthetic Approach –. Mathematical System Theory, Volume 14, pp. 97–139.

[Mac Lane 71] Mac Lane, S. (1971): Categories for the Working Mathematician. Grad-

uate Texts in Mathematics 5, Springer-Verlag. [Manes 76] Manes, E. G. (1976): Algebraic Theories. Graduate Texts in Mathematics

26, Springer-Verlag. [Martin-Löf 79] Martin-Löf, P. (1979): Constructive Mathematics and Computer Pro-

gramming. Paper presented in 6th International Congress for Logic, Methodology and Philosophy of Science.

[Mendler 86] Mendler N. P. (1986): First- and Second-Order Lambda Calculi with Recursive Types. Technical Report TR 86-764, Department of Computer Science, Cornell University.

[Milner 84] Milner, R. (1984): The Standard ML Core Language. Internal Report CSR-

168-84, Department of Computer Science, University of Edinburgh. [Parasaya-Ghomi 82] Parasaya-Ghomi, K. (1982): Higher Order Abstract Data Types.

Ph. D. Thesis, Department of Computer Science, UCLA. [Plotkin 81] Plotkin, G. D. (1981): A Structural Approach to Operational Semantics.

Technical Report DAIMI FN–19, Computer Science Department, Århus University. [Rydeheard 81] Rydeheard, D. E. (1981): Application of Category Theory to Program-

ming and Program Specification. Ph. D. thesis, University of Edinburgh. [Rydeheard and Burstall 86] Rydeheard, D. E. and Burstall, R. M. (1986): Computa-

tional Category Theory. [Scott 76] Scott, D. (1976): Data Types as Lattices. SIAM Journal of Computing,

Volume 5, pp. 552–587. [Smyth and Plotkin 82] Smyth, M. B. and Plotkin, G. D. (1982): The Category-

Theoretic Solution of Recursive Domain Equations. SIAM Journal of Computing, Volume 11.

[Stenlund 72] Stenlund, S. (1972): Combinators, λ-Terms and Proof Theory. D. Reidel,

Dordrecht. [Stoy 77] Stoy, J. E. (1977): The Scott-Strachey Approach to Programming Language

Theory. MIT Press. [Tait 67] Tait, W. (1967): Intentional Interpretation of Functionals of Finite Type I.

Journal of Symbolic Logic, 32, pp. 198–212.

[Troelstra 73] Troelstra, A. S. (1973): Mathematical Investigation of Intuitionistic Arithmetic and Analysis. Lecture Notes in Mathematics, Volume 344, Springer-Verlag.

Declaration

This thesis has been written by myself, and the work is my own. Edinburgh, 1 June 1987

Tatsuya Hagino