D. Plaindoux | ScalaIO 2024
A dependent type is a type whose 
 definition depends on a value
All combinations with λC or Calculus of Constructions
        
            
        
  P0 ... Pn      when premisses P0 ... Pn are verified
  ---------      then
  C              we conclude C
            
        
  P0 ... Pn      when premisses P0 ... Pn are verified
  ---------      then
  C              we conclude C
  Γ              type bindings i.e. hypothesis
            
        
  P0 ... Pn      when premisses P0 ... Pn are verified
  ---------      then
  C              we conclude C
  Γ              type bindings (X : T) i.e. hypothesis
  Γ ⊢ A : T      Given Γ, the term A inhabits the type T
            
        
    x ∈ Variables
    i ∈ Identifiers
            
        
    x ∈ Variables
    i ∈ Identifiers
    e ::=
         λ(x).e                 -- Abstraction
         e e                    -- Application
         x                      -- Variable
            
        
    x ∈ Variables
    i ∈ Identifiers
    e ::=
         λ(x).e                 -- Abstraction
         e e                    -- Application
         x                      -- Variable
    t ::=
         i                      -- Basic types
         t → t                  -- Function type
            
        λ-expressions: abstraction and application
M → N
    Γ, x : M ⊢ b : N
    -------------------
    Γ ⊢ λ(x).b : M → N
            
        M → N
    Γ, x : M ⊢ b : N
    -------------------
    Γ ⊢ λ(x).b : M → N
    Γ ⊢ f : M → N   Γ ⊢ e : M
    --------------------------
    Γ ⊢ f e : N
            
        
    x ∈ Variables
    i ∈ Identifiers
    e ::=
         λ(x).e                 -- Abstraction
         e e                    -- Application
         x                      -- Variables
    t ::=
         i                      -- Basic types (int, ...)
         t → t                  -- Function type
            
        
    x ∈ Variables
    i ∈ Identifiers
    e ::=
         λ(x).e                 -- Abstraction
         e e                    -- Application
         x                      -- Variables
         i                      -- Basic types (int, ...)
         e → e                  -- Function type
            
        
    x ∈ Variables
    i ∈ Identifiers
    e ::=
         λ(x).e                 -- Abstraction
         e e                    -- Application
         x                      -- Variables
         i                      -- Basic types (int, ...)
         e → e                  -- Function type
         Π(x:e).e               -- Dependent functional type
         type                   -- type of type
            
        
    x ∈ Variables
    i ∈ Identifiers
    e ::=
         λ(x).e                 -- Abstraction
         e e                    -- Application
         x                      -- Variables
         i                      -- Basic types (int, ...)
         e → e                  -- ≡ Π(_:e).e
         Π(x:e).e               -- Dependent functional type
         type                   -- type of type
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N
    --------------------------------
    Γ ⊢ λ(x).b : M → N
    Γ ⊢ f : M → N   Γ ⊢ e : M
    --------------------------
    Γ ⊢ f e : N
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N
    --------------------------------
    Γ ⊢ λ(x).b : Π(_:M).N
    Γ ⊢ f : Π(_:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N
    --------------------------------
    Γ ⊢ λ(x).b : Π(x:M).N
    Γ ⊢ f : Π(_:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N   Γ ⊢ M : type
    --------------------------------
    Γ ⊢ λ(x).b : Π(x:M).N
    Γ ⊢ f : Π(_:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N   Γ ⊢ M : type
    --------------------------------
    Γ ⊢ λ(x).b : Π(x:M).N
    Γ ⊢ f : Π(x:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N   Γ ⊢ M : type
    --------------------------------
    Γ ⊢ λ(x).b : Π(x:M).N
    Γ ⊢ f : Π(x:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N[x:=e]
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N   Γ ⊢ M : type
    --------------------------------
    Γ ⊢ λ(x).b : Π(x:M).N
    Γ ⊢ f : Π(x:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N[x:=e]
    Γ ⊢ M : ?      Γ, x : M ⊢ N : ?
    -----------------------------------
    Γ ⊢ Π(x:M).N : ?
            
        Π(x:M).Ntype of return value varies with its argument
    Γ, x : M ⊢ b : N   Γ ⊢ M : type
    --------------------------------
    Γ ⊢ λ(x).b : Π(x:M).N
    Γ ⊢ f : Π(x:M).N   Γ ⊢ e : M
    -----------------------------
    Γ ⊢ f e : N[x:=e]
    Γ ⊢ M : type   Γ, x : M ⊢ N : type
    -----------------------------------
    Γ ⊢ Π(x:M).N : type
            
        
    -- A → B ≡ Π(_:A).B
    sig id_t : ?
    val id_t = λ(X).X → X
            
        
    -- A → B ≡ Π(_:A).B
    sig id_t : type → type
    val id_t = λ(X).X → X
            
        
    -- A → B ≡ Π(_:A).B
    sig id_t : type → type
    val id_t = λ(X).X → X
    sig combine : Π(A:type).A → A → A
            
        
    -- A → B ≡ Π(_:A).B
    sig id_t : type → type
    val id_t = λ(X).X → X
    sig combine : Π(A:type).A → A → A
    sig incr : int → int
    val incr = combine int 1
            
        
    -- A → B ≡ Π(_:A).B
    sig id_t : type → type
    val id_t = λ(X).X → X
    sig combine : Π(A:type).A → A → A
    sig incr : id_t int
    val incr = combine int 1
            
        
    -- A → B ≡ Π(_:A).B 
    sig select : int → type
    -- with select 0 = string and
    --      select i = char for i != 0
            
        
    -- A → B ≡ Π(_:A).B 
    sig select : int → type
    -- with select 0 = string and
    --      select i = char for i != 0
    sig aString : string
    val aString = "Hello World 👋"
    sig aChar   : char
    val aChar   = '😀'
            
        
    -- A → B ≡ Π(_:A).B 
    sig select : int → type
    -- with select 0 = string and
    --      select i = char for i != 0
    sig aString : select 0
    val aString = "Hello World 👋"
    sig aChar   : select 1
    val aChar   = '😀'
            
        
    e ::=
         ...
         e , e                  -- Pair
         fst e                  -- Left projection
         snd e                  -- Right projection
         ...
         e * e                  -- Pair type
            
        M * N
    Γ ⊢ a : M   Γ ⊢ b : N
    ----------------------
    Γ ⊢ a , b : M * N
    Γ ⊢ e : M * N           Γ ⊢ e : M * N
    --------------          ----------------
    Γ ⊢ fst e : M           Γ ⊢ snd e : N
            
        
    e ::=
         ...
         e , e                  -- Pair
         fst e                  -- Left projection
         snd e                  -- Right projection
         ...
         e * e                  -- Pair type
            
        
    e ::=
         ...
         e , e                  -- Pair
         fst e                  -- Left projection
         snd e                  -- Right projection
         ...
         e * e                  -- ≡ Σ(_:e).e
         Σ(x:e).e               -- Dependent pair type
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N
    -------------------------------------------
    Γ ⊢ a , b : M * N
    Γ ⊢ p : M * N             Γ ⊢ p : M * N
    -------------             -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N
    -------------------------------------------
    Γ ⊢ a , b : Σ(_:M).N
    Γ ⊢ p : Σ(_:M).N          Γ ⊢ p : Σ(_:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(_:M).N          Γ ⊢ p : Σ(_:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N         Γ ⊢ M : type
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(_:M).N          Γ ⊢ p : Σ(_:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N[x:=a]   Γ ⊢ M : type
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(_:M).N          Γ ⊢ p : Σ(_:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N[x:=a]   Γ ⊢ M : type
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(x:M).N          Γ ⊢ p : Σ(_:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N[x:=a]   Γ ⊢ M : type
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(x:M).N          Γ ⊢ p : Σ(x:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N[x:=a]   Γ ⊢ M : type
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(x:M).N          Γ ⊢ p : Σ(x:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N[x:=fst p]
            
        Σ(x:M).Ntype of right value varies with its left value
    Γ ⊢ a : M   Γ ⊢ b : N[x:=a]   Γ ⊢ M : type
    -------------------------------------------
    Γ ⊢ a , b : Σ(x:M).N
    Γ ⊢ p : Σ(x:M).N          Γ ⊢ p : Σ(x:M).N
    -----------------         -----------------------
    Γ ⊢ fst p : M             Γ ⊢ snd p : N[x:=fst p]
    Γ ⊢ M : type   Γ, x : M ⊢ N : type
    -----------------------------------
    Γ ⊢ Σ(x:M).N : type
            
        
    sig pair : ?
    val pair = char , '🐶'
            
        
    sig pair : type * char
    val pair = char , '🐶'
            
        
    sig pair : Σ(x:type).char
    val pair = char , '🐶'
            
        
    sig pair : Σ(x:type).x
    val pair = char , '🐶'
            
        
    sig pair : Σ(x:type).x
    val pair = char , '🐶'
    sig first : type
    val first = fst pair
            
        
    sig pair : Σ(x:type).x
    val pair = char , '🐶'
    sig first : type
    val first = fst pair
    sig second : ?
    val second = snd pair
            
        
    sig pair : Σ(x:type).x
    val pair = char , '🐶'
    sig first : type
    val first = fst pair
    sig second : char
    val second = snd pair
            
        
    sig pair : Σ(x:type).x
    val pair = char , '🐶'
    sig first : type
    val first = fst pair
    sig second : char -- char ≡ fst pair (i.e. x[x:=fst pair]) 
    val second = snd pair
            
        
    sig pair : Σ(x:type).x
    val pair = (char , '🐶')
    sig first : type
    val first = fst pair
    sig second : fst pair
    val second = snd pair
            
        
    x ∈ Variables
    e ::=
         ...
         inl e                  -- Left injection
         inr e                  -- Right injection
         case x e e             -- Catamorphism
         ...
         e + e                  -- Sum type
            
        
    Γ ⊢ a : ?                  Γ ⊢ a : ?
    ------------------         ------------------
    Γ ⊢ inl a : ?              Γ ⊢ inr a : ?
    Γ ⊢ a : ?
    Γ ⊢ l : ?                    Γ ⊢ r : ?
    --------------------------------------------------------
    Γ ⊢ case a l r : P
            
        
    Γ ⊢ a : M                  Γ ⊢ a : ?
    ------------------         ------------------
    Γ ⊢ inl a : M + N          Γ ⊢ inr a : ?
    Γ ⊢ a : ?
    Γ ⊢ l : ?                    Γ ⊢ r : ?
    --------------------------------------------------------
    Γ ⊢ case a l r : P
            
        
    Γ ⊢ a : M                  Γ ⊢ a : N
    ------------------         ------------------
    Γ ⊢ inl a : M + N          Γ ⊢ inr a : M + N
    Γ ⊢ a : ?
    Γ ⊢ l : ?                    Γ ⊢ r : ?
    --------------------------------------------------------
    Γ ⊢ case a l r : P
            
        
    Γ ⊢ a : M                  Γ ⊢ a : N
    ------------------         ------------------
    Γ ⊢ inl a : M + N          Γ ⊢ inr a : M + N
    Γ ⊢ a : M + N
    Γ ⊢ l : Π(x:M).P             Γ ⊢ r : Π(x:N).P
    --------------------------------------------------------
    Γ ⊢ case a l r : P
            
        
    Γ ⊢ a : M                  Γ ⊢ a : N
    ------------------         ------------------
    Γ ⊢ inl a : M + N          Γ ⊢ inr a : M + N
    Γ ⊢ a : M + N
    Γ ⊢ l : Π(x:M).P[a:=inl x]   Γ ⊢ r : Π(x:N).P[a:=inr x]
    --------------------------------------------------------
    Γ ⊢ case a l r : P
            
        
    Γ ⊢ a : M                  Γ ⊢ a : N
    ------------------         ------------------
    Γ ⊢ inl a : M + N          Γ ⊢ inr a : M + N
    Γ ⊢ a : M + N
    Γ ⊢ l : Π(x:M).P[a:=inl x]   Γ ⊢ r : Π(x:N).P[a:=inr x]
    --------------------------------------------------------
    Γ ⊢ case a l r : P
    Γ ⊢ M : type    Γ ⊢ N : type
    -----------------------------
    Γ ⊢ M + N : type
            
        
    sig int_or_char : int + char → type
    val int_or_char = λ(x).case x λ(_).char λ(_).int
    sig aChar : char
    val aChar = '🌊'
            
        
    sig int_or_char : int + char → type
    val int_or_char = λ(x).case x λ(_).char λ(_).int
    sig aChar : int_or_char (inl 1)
    val aChar = '🌊'
            
        
    sig bool : type
    val bool = Unit + Unit
            
        
    sig bool : type
    val bool = Unit + Unit
    sig true  : bool
    val true  = inl unit
    sig false : bool
    val false = inr unit
            
        
    sig bool : type
    val bool = Unit + Unit
    sig true  : bool
    val true  = inl unit
    sig false : bool
    val false = inr unit
    sig Test : bool → type
    val Test = λ(b).case b λ(_).int λ(_).char
            
        
    sig bool : type
    val bool = Unit + Unit
    sig true  : bool
    val true  = inl unit
    sig false : bool
    val false = inr unit
    sig Test : bool → type
    val Test = λ(b).case b λ(_).int λ(_).char
    sig test : Π(b:bool).?
    val test = λ(c).case c λ(_).1 λ(c).'🫣'
            
        
    sig bool : type
    val bool = Unit + Unit
    sig true  : bool
    val true  = inl unit
    sig false : bool
    val false = inr unit
    sig Test : bool → type
    val Test = λ(b).case b λ(_).int λ(_).char
    sig test : Π(b:bool).(Test b)
    val test = λ(c).case c λ(_).1 λ(c).'🫣'
            
        Intentional type theory
    e ::=
         ...
         refl                   -- Reflexivity
         ...
         e = e                  -- type equality
            
        Intentional type theory
    e ::=
         ...
         refl                   -- Reflexivity
         subst e by e           -- Substitution
         ...
         e = e                  -- type equality
            
        
    Γ ⊢ n : A    Γ ⊢ m : A
    -----------------------
    Γ ⊢ n = m : type
            
        
    Γ ⊢ n : A    Γ ⊢ m : A
    -----------------------         -----------------
    Γ ⊢ n = m : type                Γ ⊢ refl : m = m
            
        
    Γ ⊢ n : A    Γ ⊢ m : A
    -----------------------         -----------------
    Γ ⊢ n = m : type                Γ ⊢ refl : m = m
    Γ ⊢ b : x = B    Γ ⊢ a : A[x:=B]
    ---------------------------------
    Γ ⊢ subst a by b : A
    Γ ⊢ b : B = x    Γ ⊢ a : A[x:=B]
    ---------------------------------
    Γ ⊢ subst a by b : A
            
        
    sig reflexive : Π(A:type).Π(a:A).(a = a)
    val reflexive = λ(_).λ(a).refl
            
        
    sig reflexive : Π(A:type).Π(a:A).(a = a)
    val reflexive = λ(_).λ(a).refl
    sig symmetric : Π(A:type).Π(a:A).Π(b:A).(a = b → b = a)
    val symmetric = λ(_).λ(a).λ(b).λ(a=b).?
            
        
    sig reflexive : Π(A:type).Π(a:A).(a = a)
    val reflexive = λ(_).λ(a).refl
    sig symmetric : Π(A:type).Π(a:A).Π(b:A).(a = b → b = a)
    val symmetric = λ(_).λ(a).λ(b).λ(a=b).(subst refl by a=b)
            
        
    -{
     data Expr A =
     | Boolean of bool with A = bool
     | Integer of int  with A = int
    }-
    sig Expr : type → type
    val Expr = ?
            
        
    -{
     data Expr A =
     | Boolean of bool with A = bool
     | Integer of int  with A = int
    }-
    sig Expr : type → type
    val Expr = λ(A).((A = bool) * bool) + ((A = int) * int)
            
        
    sig Expr : type → type
    val Expr = λ(A).((A = bool) * bool) + ((A = int) * int)
            
        
    sig Expr : type → type
    val Expr = λ(A).((A = bool) * bool) + ((A = int) * int)
    sig Boolean : Π(A:type).Π(_:A = bool).(bool -> Expr A)
    val Boolean = λ(_).λ(p).λ(b).inl (p,b)
            
        
    sig Expr : type → type
    val Expr = λ(A).((A = bool) * bool) + ((A = int) * int)
    sig Boolean : Π(A:type).Π(_:A = bool).(bool -> Expr A)
    val Boolean = λ(_).λ(p).λ(b).inl (p,b)
    sig Integer : Π(A:type).Π(_:A = int).(int -> Expr A)
    val Integer = λ(_).λ(p).λ(i).inr (p,i)
            
        
    sig Expr : type → type
    val Expr = λ(A).((A = bool) * bool) + ((A = int) * int)
    sig Boolean : Π(A:type).Π(_:A = bool).(bool -> Expr A)
    val Boolean = λ(_).λ(p).λ(b).inl (p,b)
    sig Integer : Π(A:type).Π(_:A = int).(int -> Expr A)
    val Integer = λ(_).λ(p).λ(i).inr (p,i)
    sig one_expr : Expr int
    val one_expr : Integer int refl 1
            
        Think different!