Domain models and their values
Refinements types?
separation of Adequecy
Signature morphisms
Programer defined Index Domains http://dlicata.web.wesleyan.edu/pubs/lh05concert-talk/lh05concert-talk.pdf
2 levels (representation vs computation)?
need for a modal logic?
representation invariants
Adequacy of representation via logical relations (to a correct impl)
See views feature request of succML (B.20) https://people.mpi-sws.org/~rossberg/hamlet/hamlet-succ-1.3.1S5.pdf i.e.:
Static meta programming
Programming & thm proving https://www.cs.bu.edu/~hwxi/academic/papers/icfp05.pdf
Set types (from nuprl)
LF works because you're representing a logic or language in its totality
Does twelf style goal directed search + unification (asusming term reconstruction) drive target language interpretation? e.g. are we just searching for a target type / target type converter given a type?
e.g.
JavaType
toJavaRep: (t:Type) -> JavaType(t) toJavaRep(Int) = JavaLong javaLong: (i:Int) -> JavaLong but we need to capture the value?
Can definition n = 4
just be made n : \[].4
or n : (\[x].x)(4)
do we allow single element tuples (rather than bare values)?
Encode target language features as types / functors https://brianmckenna.org/blog/polymorphic_programming
Let path'ed identifiers have a "module part" and a "decl part"
Internal types (LF / Lam_pi types) have a target representation
Related problem, when to treat a type as atomic / ground vs when to peer into its def.
eg: Nat: Type = {z, s(n)} Ord, Eq... Bounded <...> : Type Int32 = Bounded<Nat, min, max> Int64 = Bounded<Nat, min, max> Int = Int64 // convenience
Sometimes we just care that Int can be represented by an int 64
Sometimes we want to prove things about the underlying Nat structure, up to the bounds "type refinement"
How does the subtyping relationship work here? Int is a Nat
\x:Int -> Nat
ie an LF lam-termHow do I choose value representations
Would be cool to allow modules to gradually open up
maybe I just care about "programming" an int64 is an int64
maybe I care to verify deeper properties e.g: "import module ring" and suddenly an Int can be treated with properties of rings / fields eg: by default we have Nat : Type // it's a type but we have no details Bounded ... Int32 = Int64 = Int = Int64
we somehow allow numerals to be intrinsic constructors of Int
n : Int32 = 2
or n = 2 : Int32
?What are the search constraints to guide goals that Int is a valid "ground"
A language for expressing and communicating ideas but not how to define the processes behind them.
Note: separation of primitive types vs primitive vals
->
)
Vec<T:Type, size:Int>
?
types
values (constants)
everything is in normal form (there's no dynamics)
modules
Allow alias defs via :=
ie what twelf calls %abbrev
. ie: sbustitute immediately
How to deal with recursive types / data types (ie abstract types) / modules / frozen inductive definitions
Are the primitive tuples dependent?
Here's a few snippets of runway code and how to informally read it (in our heads or aloud). We often want to know how to "pronounce" phrases without getting bogged down in the technicalities of the actual math and type theory.
We'll leave pointers about the underlying terminology so the curious know where to look.
The main idea is that we want to simply stating things we know (or might want to know). We get the computer fill in any gaps or point out inconsistencies.
Asside: Statements about things we know are called judgments.
We have 2 very basic kinds of statements that express 2 primitive relationships
When you see =
think "is".
Left to right: "is equal to", "is defined to be", "is identical to", "is the same as", "is identified with", "is solved by"
Right to left: "is the definition of", "is the solution to", "can stand for", "can be substituted for"
n = 5
n
is 5
(an Int
)5
can stand for n
(whenever I see n
from now on)*name = "James"
name
is "James"
(a String
)"James"
can stand for name
(whenever I see name
from now on)*It's tempting to think we're just assigning values to constants but its more useful to think of identification as a solution to an equation like you might remember from high-shool math (e.g. x = 4y + 5). You're stating a relationship about the left and right hand sides of the equation. In the simple cases above the solution is trivial assignment.
When you see :
think "is a"
Left to right: "is a member of", "is an element of"
Rgith to left: xxx
n : Int
n
is an Int
Int
(1
, 2
, 3
...) can be assigned to n
(but nothing else)Int
classifies n
n
must come from the domain of values defined by Int
tuples are primitive
are tagged tuples primitive? What's the syntax?
Sym (some, tuple)
how is this not fn app?Sym of (some, tuple)
Sym with (some, tuple)
Sym(s,t)
where S: (some, tuple) -> T
('Sym, (s, t)) : T
T = ('c1, (a, b, c)) | ('c2, (d, e))
i.e. a union type that's made disjoint because T.fst
is c1
or c2
the value of c1 / c2 can be anything, the name of the ctor or the
actual function eg c1 : (A, B, C) -> T
and c2 : (D, E) -> T
T = ('c1, (A, B, C)) | ('c2, (D, E))
c1 <r:Type> : r -> T<'c1, r>
?CTor <name:String, repr:Type, res:String -> Type -> Type> : r -> res<name, r>
T.Tag : Type
; Review regular sum types, how would this work in dep-type land?
Regular fun
A -> B
, (A, B, C) -> D
Dep fun
(a:A) => B(a)
, (a:A, B, C) => D(a)
Regular tuple
(a, b) : (A, B)
(and all the other fun keyword stuff from swift)
Dep pair?
(a, mkB(a)) : (a:A; B(a))
semicolon in the type, do we care about it in the literal?
(A, B(x=a))
can always be the result of a dep-fnFoo = (Int, Int)
Foo : Type
On the fly tags (assuming Foo enumerated data type)? How does twelf's nat work under the hood?
want something like:
Nat : Type z : Nat s : Nat -> Nat %freeze (the structural inductive type definition but not other uses of nat)
Nat : Type = { z : Nat s : Nat -> Nat }
What about
Nat = {z, s: Nat -> Nat}
Nat : Type = {z, s: Nat -> Nat}
Nat = {z: Nat, s: Nat -> Nat}
Nat = {z, s(n:Nat)}
Nat = {z, s
eg: Bool = {True, False} Bool = {True. False.}
Foo_Tag : Type c1:Foo_Tag c2:Foo_Tag %freeze
// Most direct Foo_Tag : Type = { c1:Foo_Tag c2:Foo_Tag }
// ? Foo_Tag = { c1:Foo_Tag c2:Foo_Tag } : Type // ?
Foo_Tag : Type = {c1, c2} Foo_Tag = {c1, c2} : Type Foo_Tag:Type = c1 | c2
// type alias is not what we want Person = (name:String, age:Int)
Person = { name: String age: Int }
// ^^^ incompatible with vvv
// ie: the Foo : Type = sig
form
Foo = {
Foob: (i:Int) -> Foo
Fab: (s:String, i:Int) -> Foo
}
Non-disjoint sum is common - should it be streamlined?
Person = { new : (name:String, age:Int) -> Person }
p = Person.new(....) // vs p = Person(...)
Tedious to always 1) choose a name for the constructor 2) Specify the return type 3) the call site name isn't what we want for the definition site // alternatives new, of, from, with, as, init, get
constructor
keyword like idris?do we want an alternate form?
Person = data { | _ of (name:String, age:Int) }
Bool = { true: bool false: bool }
Bool = data { | true | false }
or also allow a one liner Bool = data {true | false}
or just Bool = data true | false
MaybeInt = { none: MaybeInt some: Int -> MaybeInt }
MaybeInt = data { | none | some(Int) }
// Does the above allow proper induction? // The above feels too nuts and bolts, I don't really care about a tuple of value constructors // It also looses the idea of a tagged tuple
Foo = { | Foob (i:Int) | Floop (i:Int) | Fab (s:String, i:Int) }
// Does the following allow any form of data abstraction? Foo = Foob (i:Int) | Fab (s:String, i:Int)
Foo = data | Foob (i:Int) | Fab (s:String, i:Int)
Foo = | Foob (i:Int) | Fab (s:String, i:Int)
Elaborates to => Option 1) Person: Type Person.new: (name:String, age:Int) -> Person
Option 2)
Questions about data types
Person: (T:Type, new:(name:String, age:Int) -> T)
p1 : Person
and have it mean Person.T
(not the tuple)p1 = Person(name = "Shawn", age = 34)
rather than p1 = Person.new(...)
Best shown by example:
```
List <elem:Type> : Type
> List : (elem:Type) -> Type
List(String)
> List(String) : Type
StringList = List(String)
> StringList : ??? List(String)
l : StringList
> l : List(String)
```
Pattern:
Foo <t:Type> : Type
Read typically:
Read logically:
Elaborates to:
=> Foo : (t:Type) -> Type
=> Foo(String) : Type
Note: Foo is a type constructor (in the sense that it's a function Type -> Type)
Just move the :
for the curried vs un-curried form.
Note: Functions capture the concept of hypothetical
More examples
List <elem:Type> : Type
=> List : (elem:Type) -> Type
Vec <elem:Type, count:Int> : Type
=> `e
Reads Foo
// Tuple is a kind family Tuple0: () -> Type Tuple1: Type -> Type Tuple2: Type -> Type -> Type
// Foo:Tuple<Type, Type>
tuple: [Type -> Type
type Foo = (int, int) Foo = (int, int)
Foo : (Type, Type) = (Int, Int) // do we also also have a TyCon Foo:Int -> Int -> Type
(1,2):Foo (1,2):(int, int)
bar = 5
bar = 5 : Int
// ie: bar : Int and 5 :
// ie == <t:Type> : (t, t) -> Bool
Person = (name: String)
Person : Type = (name : String) did I introduce a tyocon in the equation above? Person(name = foo)?
Maybe:
Maybe = data
Mabye : Type -> Type None : Maybe Some