-
Notifications
You must be signed in to change notification settings - Fork 0
/
TODO
129 lines (88 loc) · 4 KB
/
TODO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
Desired type system extensions:
0. Stable/dynamic datatypes
1. Abstract types
2. Mutually recursive definitions
3. Explicit polymorphic abstractions
4. Type definitions
5. Higher-kinded polymorphism
6. Records
7. Arrays
8. Index domains
9. Disjunctive linear datatypes
10. GADTs
11. Row polymorphism
12. Implicit/qualified types
13. Dependent types
Questions:
0. Syntax for kind annotations
We want to leave off kind annotations if possible. This means introducing kind evars
into our context, which is easy. What is harder is the syntax for kind annotations.
This is Coq-style:
forall (a b : int), (c d : lin). (a -> b) -> G(c -o d)
We can also explicitly parenthesize and annotates each tycon needing annotation:
forall a b c (d : int -> int) e. a -> b -> d c
I will try the latter form for now, with the option of changing it to
something less noisy later.
1. Can we accomodate type definitions *without* necessarily having type-level lambdas?
1a. We can do this by requiring that all type definitions be fully applied when they
are used. As a result, we can give a definition like:
type pair : int -> int -> int
type pair a b = (a & b)
but we can only use it as "pair int int", and not as "pair". This considerably
limits the utility of such definitions. Does it restrict them too much?
1b. Another approach is to restrict subtyping for higher-kinded definitions.
We can say that
\Gamma, a:k1 |- F a <: G a : k2
-------------------------------
\Gamma |- F <: G : k1 -> k2
This means that the subtyping relation assumes that all type
definitions are potentially co- and contra-variant. As as a result,
we do not need to make any hypotheses about the variance of the
type constructors.
Then the subtyping relation at higher kind just eta-expands until
it hits a base kind, and then unfolding a definition will never
leave us with a lambda.
This subsumes 1a, while still blocking type-level lambda
abstractions. The question is: how does this interact with
stability?
So the only substitution rule remains the same:
\Gamma |-* \Gamma(A) <: \Gamma(B) : b
---------------------------------------
\Gamma |- A <: B : b
We should represent applications in spine form to make this work
nicely.
1. Do we need subkinding between stable and dynamic types, or can
we get away without it?
I don't want it. I have enough subtyping already, and subkinding
will screw up dependent types when I add it. Implicit/qualified
types can handle the reasonable uses by letting us pass stability
constraints as arguments.
1' How about the stability flags on datatypes?
We can declare datatypes to be *stable*, which means that every
branch is a stable type, assuming that all the type arguments are
stable. Consider:
stable type list a = Nil of unit | Cons of (a & list a)
Now, we assume a is stable, that list is a stable type constructor.
Note that unit is stable, and (a & list a) is stable if a and list
a are stable. We assumed a is stable, so this leaves showing list a
is stable. However, we assumed list is a stable type constructor,
so applying it to the stable type a gives a stable type.
This means each type variable needs to carry a
2. How can we handle explicit type applications? (For fullly
impredicative applications.)
1. put term-level applications in spine form.
2. Add a head marker (ala Coq) to switch to explicit
mode.
3. Syntax of explicit type applications:
val id : forall a. a -> a
let id a x = x
Then we can write:
@(map ~num ~num (fun x -> x + x) (Cons(3, Cons(4, Nil))))
vs
map (fun x -> x) (Cons(3, Cons(4, Nil)))
or even
@(id ~(forall a. a -> a) id) : (forall a. a -> a)
3. Records
The obvious thing is Morrow-style row polymorphism. There are
questions about how to map records with duplicated labels to JS
objects.