LogRel.AlgorithmicJudgments: definition of conversion (typed and untyped

From Coq Require Import ssrbool.
From LogRel Require Import Utils Syntax.All GenericTyping.

Section Definitions.

We locally disable typing notations to be able to use them in the definition here before declaring the right instance.
  Close Scope typing_scope.

Typed conversion

Conversion of types

  Inductive ConvTypeAlg : context -> term -> term -> Type :=
    | typeConvRed {Γ A A' B B'} :
      [A ⤳* A'] ->
      [B ⤳* B'] ->
      [Γ |- A' h B'] ->
      [Γ |- A B]
  

Conversion of types reduced to weak-head normal forms

  with ConvTypeRedAlg : context -> term -> term -> Type :=
    | typePiCongAlg {Γ A B A' B'} :
      [ Γ |- A A'] ->
      [ Γ ,, A |- B B'] ->
      [ Γ |- tProd A B h tProd A' B']
    | typeUnivConvAlg {Γ} :
      [Γ |- U h U]
    | typeNatConvAlg {Γ} :
      [Γ |- tNat h tNat]
    | typeEmptyConvAlg {Γ} :
      [Γ |- tEmpty h tEmpty]
    | typeSigCongAlg {Γ A B A' B'} :
      [ Γ |- A A'] ->
      [ Γ ,, A |- B B'] ->
      [ Γ |- tSig A B h tSig A' B']
    | typeIdCongAlg {Γ A A' x x' y y'} :
      [ Γ |- A A'] ->
      [ Γ |- x x' : A] ->
      [ Γ |- y y' : A] ->
      [ Γ |- tId A x y h tId A' x' y']
    | typeNeuConvAlg {Γ M N T} :
      whne M ->
      whne N ->
      [ Γ |- M ~ N T] ->
      [ Γ |- M h N]
  

Conversion of neutral terms

  with ConvNeuAlg : context -> term -> term -> term -> Type :=
    | neuVarConvAlg {Γ n decl} :
      in_ctx Γ n decl ->
      [Γ |- tRel n ~ tRel n decl]
    | neuAppCongAlg {Γ m n t u A B} :
      [ Γ |- m ~h n tProd A B ] ->
      [ Γ |- t u : A ] ->
      [ Γ |- tApp m t ~ tApp n u B[t..] ]
    | neuNatElimCong {Γ n n' P P' hz hz' hs hs'} :
    
Here, we know by invariant that the inferred type has to be tNat, so there should be no need to check that, but with parameterized/indexed inductive we need to recover informations from the neutrals to construct the context for the predicate and the type of the branches.
      [Γ |- n ~h n' tNat] ->
      [Γ,, tNat |- P P'] ->
      [Γ |- hz hz' : P[tZero..]] ->
      [Γ |- hs hs' : elimSuccHypTy P] ->
      [Γ |- tNatElim P hz hs n ~ tNatElim P' hz' hs' n' P[n..]]
| neuEmptyElimCong {Γ P P' e e'} :
      [Γ |- e ~h e' tEmpty] ->
      [Γ ,, tEmpty |- P P'] ->
      [Γ |- tEmptyElim P e ~ tEmptyElim P' e' P[e..]]
| neuFstCongAlg {Γ m n A B} :
      [ Γ |- m ~h n tSig A B ] ->
      [ Γ |- tFst m ~ tFst n A ]
    | neuSndCongAlg {Γ m n A B} :
      [ Γ |- m ~h n tSig A B ] ->
      [ Γ |- tSnd m ~ tSnd n B[(tFst m)..] ]
    | neuIdElimCong {Γ A A' A'' x x' x'' P P' hr hr' y y' y'' e e'} :
      [Γ |- e ~h e' tId A'' x'' y''] ->
      [Γ ,, A ,, tId A@wk1 Γ A x@wk1 Γ A (tRel 0) |- P P'] ->
      [Γ |- hr hr' : P[tRefl A x .: x..]] ->
      [Γ |- tIdElim A x P hr y e ~ tIdElim A' x' P' hr' y' e' P[e .: y..] ]
  

Conversion of neutral terms at a type reduced to weak-head normal form

  with ConvNeuRedAlg : context -> term -> term -> term -> Type :=
    | neuConvRed {Γ m n A A'} :
      [Γ |- m ~ n A] ->
      [A ⤳* A'] ->
      whnf A' ->
      [Γ |- m ~h n A']
  

Conversion of terms

  with ConvTermAlg : context -> term -> term -> term -> Type :=
    | termConvRed {Γ t t' u u' A A'} :
      [A ⤳* A'] ->
      [t ⤳* t'] ->
      [u ⤳* u' ] ->
      [Γ |- t' h u' : A'] ->
      [Γ |- t u : A]
  

Conversion of terms reduced to a weak-head normal form at a reduced type

  with ConvTermRedAlg : context -> term -> term -> term -> Type :=
    | termPiCongAlg {Γ A B A' B'} :
      [ Γ |- A A' : U] ->
      [ Γ ,, A |- B B' : U] ->
      [ Γ |- tProd A B h tProd A' B' : U]
    | termNatReflAlg {Γ} :
      [Γ |- tNat h tNat : U]
    | termZeroReflAlg {Γ} :
      [Γ |- tZero h tZero : tNat]
    | termSuccCongAlg {Γ t t'} :
      [Γ |- t t' : tNat] ->
      [Γ |- tSucc t h tSucc t' : tNat]
    | termEmptyReflAlg {Γ} :
      [Γ |- tEmpty h tEmpty : U]
    | termFunConvAlg {Γ : context} {f g A B} :
      whnf f ->
      whnf g ->
      [ Γ,, A |- eta_expand f eta_expand g : B] ->
      [ Γ |- f h g : tProd A B]
    | termSigCongAlg {Γ A B A' B'} :
      [ Γ |- A A' : U] ->
      [ Γ ,, A |- B B' : U] ->
      [ Γ |- tSig A B h tSig A' B' : U]
    | termPairConvAlg {Γ : context} {p q A B} :
      whnf p ->
      whnf q ->
      [ Γ |- tFst p tFst q : A] ->
      [ Γ |- tSnd p tSnd q : B[(tFst p)..]] ->
      [ Γ |- p h q : tSig A B]
    | termIdCongAlg {Γ A A' x x' y y'} :
      [Γ |- A A' : U] ->
      [Γ |- x x' : A] ->
      [Γ |- y y' : A] ->
      [Γ |- tId A x y h tId A' x' y' : U]
    | termIdReflCong {Γ A A' A'' x x' y y'} :
      [Γ |- tRefl A x h tRefl A' x' : tId A'' y y' ]
    | termNeuConvAlg {Γ m n T P} :
      [Γ |- m ~ n T] ->
      isPosType P ->
      [Γ |- m h n : P]

  where "[ Γ |- A ≅ B ]" := (ConvTypeAlg Γ A B)
  and "[ Γ |- A ≅h B ]" := (ConvTypeRedAlg Γ A B)
  and "[ Γ |- m ~ n ▹ T ]" := (ConvNeuAlg Γ T m n)
  and "[ Γ |- m ~h n ▹ T ]" := (ConvNeuRedAlg Γ T m n)
  and "[ Γ |- t ≅ u : T ]" := (ConvTermAlg Γ T t u)
  and "[ Γ |- t ≅h u : T ]" := (ConvTermRedAlg Γ T t u)
  and "[ t ⤳ t' ]" := (OneRedAlg t t')
  and "[ t ⤳* t' ]" := (RedClosureAlg t t').

Typing

Algorithmic typing is a parametrised by *any* conversion, so that we can use both typed and untyped conversion.
  Context `{ConvType}.

Type well-formation

  Inductive WfTypeAlg : context -> term -> Type :=
    | wfTypeU Γ : [ Γ |- U ]
    | wfTypeProd {Γ A B} :
      [Γ |- A ] ->
      [Γ,, A |- B] ->
      [Γ |- tProd A B]
    | wfTypeNat {Γ} :
      [Γ |- tNat]
    | wfTypeEmpty {Γ} :
        [Γ |- tEmpty]
    | wfTypeSig {Γ A B} :
      [Γ |- A ] ->
      [Γ,, A |- B] ->
      [Γ |- tSig A B]
    | wfTypeId {Γ A x y} :
      [Γ |- A] ->
      [Γ |- x A] ->
      [Γ |- y A] ->
      [Γ |- tId A x y]
    | wfTypeUniv {Γ A} :
      ~ isCanonical A ->
      [Γ |- A h U] ->
      [Γ |- A]
  

Type inference

  with InferAlg : context -> term -> term -> Type :=
    | infVar {Γ n decl} :
      in_ctx Γ n decl ->
      [Γ |- tRel n decl]
    | infProd {Γ} {A B} :
      [ Γ |- A h U] ->
      [Γ ,, A |- B h U ] ->
      [ Γ |- tProd A B U ]
    | infLam {Γ} {A B t} :
      [ Γ |- A] ->
      [ Γ ,, A |- t B ] ->
      [ Γ |- tLambda A t tProd A B]
    | infApp {Γ} {f a A B} :
      [ Γ |- f h tProd A B ] ->
      [ Γ |- a A ] ->
      [ Γ |- tApp f a B[a..] ]
    | infNat {Γ} :
      [Γ |- tNat U]
    | infZero {Γ} :
      [Γ |- tZero tNat]
    | infSucc {Γ t} :
      [Γ |- t h tNat] ->
      [Γ |- tSucc t tNat]
    | infNatElim {Γ P hz hs n} :
      [Γ |- n h tNat] ->
      [Γ,, tNat |- P] ->
      [Γ |- hz P[tZero..]] ->
      [Γ |- hs elimSuccHypTy P] ->
      [Γ |- tNatElim P hz hs n P[n..]]
| infEmpty {Γ} :
      [Γ |- tEmpty U]
    | infEmptyElim {Γ P e} :
      [Γ |- e h tEmpty] ->
      [Γ ,, tEmpty |- P ] ->
      [Γ |- tEmptyElim P e P[e..]]
| infSig {Γ} {A B} :
      [ Γ |- A h U] ->
      [Γ ,, A |- B h U ] ->
      [ Γ |- tSig A B U ]
    | infPair {Γ A B a b} :
      [ Γ |- A] ->
      [Γ ,, A |- B] ->
      [Γ |- a A] ->
      [Γ |- b B[a..]] ->
      [Γ |- tPair A B a b tSig A B]
    | infFst {Γ A B p} :
      [Γ |- p h tSig A B] ->
      [Γ |- tFst p A]
    | infSnd {Γ A B p} :
      [Γ |- p h tSig A B] ->
      [Γ |- tSnd p B[(tFst p)..]]
| infId {Γ A x y} :
      [Γ |- A h U] ->
      [Γ |- x A] ->
      [Γ |- y A] ->
      [Γ |- tId A x y U]
    | infRefl {Γ A x} :
      [Γ |- A] ->
      [Γ |- x A] ->
      [Γ |- tRefl A x tId A x x]
    | infIdElim {Γ A x P hr y e} :
      [Γ |- A] ->
      [Γ |- x A] ->
      [Γ,, A,, tId A@wk1 Γ A x@wk1 Γ A (tRel 0) |- P] ->
      [Γ |- hr P[tRefl A x .: x..]] ->
      [Γ |- y A] ->
      [Γ |- e tId A x y] ->
      [Γ |- tIdElim A x P hr y e P[e .: y..]]

Inference of a type reduced to weak-head normal form

  with InferRedAlg : context -> term -> term -> Type :=
    | infRed {Γ t A A'} :
      [Γ |- t A ] ->
      [ A ⤳* A'] ->
      whnf A' ->
      [Γ |- t h A']
  

Type-checking

  with CheckAlg : context -> term -> term -> Type :=
    | checkConv {Γ t A A'} :
      [ Γ |- t A ] ->
      conv_type Γ A A' ->
      [ Γ |- t A' ]

  where "[ Γ |- A ]" := (WfTypeAlg Γ A)
  and "[ Γ |- t ▹ T ]" := (InferAlg Γ T t)
  and "[ Γ |- t ▹h T ]" := (InferRedAlg Γ T t)
  and "[ Γ |- t ◃ T ]" := (CheckAlg Γ T t).

Context well-formation
  Inductive WfContextAlg : context -> Type :=
  | conNilAlg : [|- ε]
  | conConsAlg {Γ A} :
    [|- Γ] ->
    [ Γ |- A] ->
    [|- Γ,, A]
  where "[ |- Γ ]" := (WfContextAlg Γ).

End Definitions.

Untyped conversion

Conversion of types/terms: there is no distinction here

Inductive UConvAlg : term -> term -> Type :=
  | termUConvRed {t t' u u'} :
    [t ⤳* t'] ->
    [u ⤳* u' ] ->
    [t' h u'] ->
    [t u]

Conversion of types/terms reduced to a weak-head normal form

with UConvRedAlg : term -> term -> Type :=
  | UnivReflUAlg :
      [U h U]
  | PiCongUAlg {A B A' B'} :
    [A A'] ->
    [B B'] ->
    [tProd A B h tProd A' B']
  | NatReflUAlg :
    [tNat h tNat]
  | ZeroReflUAlg :
    [tZero h tZero]
  | SuccCongUAlg {t t'} :
    [t t'] ->
    [tSucc t h tSucc t']
  | EmptyReflUAlg :
    [tEmpty h tEmpty]
  | LamCongUAlg {A t A' t'} :
    [t t'] ->
    [tLambda A t h tLambda A' t']
  | LambNeUAlg {A t n'} :
    whne n' ->
    [t eta_expand n'] ->
    [tLambda A t h n']
  | NeLamUAlg {n A' t'} :
    whne n ->
    [eta_expand n t'] ->
    [n h tLambda A' t']
  | SigCongUAlg {A B A' B'} :
    [A A'] ->
    [ B B'] ->
    [tSig A B h tSig A' B']
  | PairCongUAlg {A B p q A' B' p' q'} :
    [p p'] ->
    [q q'] ->
    [tPair A B p q h tPair A' B' p' q']
  | PairNeUAlg {A B p q n'} :
    whne n' ->
    [p tFst n'] ->
    [q tSnd n'] ->
    [tPair A B p q h n']
  | NePairUAlg {n A' B' p' q'} :
    whne n ->
    [tFst n p'] ->
    [tSnd n q'] ->
    [n h tPair A' B' p' q']
  | IdCongUAlg {A A' x x' y y'} :
    [A A'] ->
    [x x'] ->
    [y y'] ->
    [tId A x y h tId A' x' y']
  | IdReflCongUAlg {A x A' x'} :
    [tRefl A x h tRefl A' x']
  | NeuConvUAlg {m n} :
    [m ~ n] ->
    [m h n]

Conversion of neutral terms

with UConvNeuAlg : term -> term -> Type :=
  | VarConvUAlg {n} :
    [tRel n ~ tRel n]
  | AppCongUAlg {m n t u} :
    [m ~ n] ->
    [t u] ->
    [tApp m t ~ tApp n u]
  | NatElimCongUAlg {n n' P P' hz hz' hs hs'} :
    [n ~ n'] ->
    [P P'] ->
    [hz hz'] ->
    [hs hs'] ->
    [tNatElim P hz hs n ~ tNatElim P' hz' hs' n']
  | EmptyElimCongUAlg {P P' e e'} :
    [e ~ e'] ->
    [P P'] ->
    [tEmptyElim P e ~ tEmptyElim P' e']
  | FstCongUAlg {m n} :
    [m ~ n] ->
    [tFst m ~ tFst n]
  | SndCongUAlg {m n} :
    [m ~ n] ->
    [tSnd m ~ tSnd n]
  | IdElimCongUAlg {A A' x x' P P' hr hr' y y' e e'} :
    [e ~ e'] ->
    [P P'] ->
    [hr hr'] ->
    [tIdElim A x P hr y e ~ tIdElim A' x' P' hr' y' e']

where "[ A ≅ B ]" := (UConvAlg A B)
and "[ A ≅h B ]" := (UConvRedAlg A B)
and "[ m ~ n ]" := (UConvNeuAlg m n).

Instances


Module AlgorithmicTypingData.

  #[export] Instance WfContext_Algo `{ta : tag} `{! ConvType ta} : WfContext ta | 100 := WfContextAlg.
  #[export] Instance WfType_Algo `{ta : tag} `{! ConvType ta} : WfType ta | 100 := WfTypeAlg.
  #[export] Instance Inferring_Algo `{ta : tag} `{! ConvType ta} : Inferring ta | 100 := InferAlg.
  #[export] Instance InferringRed_Algo `{ta : tag} `{! ConvType ta} : InferringRed ta | 100 := InferRedAlg.
  #[export] Instance Checking_Algo `{ta : tag} `{! ConvType ta} : Checking ta | 100 := CheckAlg.

  Ltac fold_algo :=
    change (@WfContextAlg ?ta _) with (wf_context (ta := ta)) in * ;
    change (@WfTypeAlg ?ta _) with (wf_type (ta := ta)) in *;
    change (@InferAlg ?ta _) with (inferring (ta := ta)) in * ;
    change (@InferRedAlg ?ta _) with (infer_red (ta := ta)) in * ;
    change (@CheckAlg ?ta _) with (check (ta := ta)) in *.

  Smpl Add fold_algo : refold.

End AlgorithmicTypingData.

Module AlgorithmicTypedConvData.

  Definition al : tag.
  Proof.
    constructor.
  Qed.

  #[export] Instance ConvType_Algo : ConvType al := ConvTypeAlg.
  #[export] Instance ConvTypeRed_Algo : ConvTypeRed al := ConvTypeRedAlg.
  #[export] Instance ConvTerm_Algo : ConvTerm al := ConvTermAlg.
  #[export] Instance ConvTermRed_Algo : ConvTermRed al := ConvTermRedAlg.
  #[export] Instance ConvNeu_Algo : ConvNeu al := ConvNeuAlg.
  #[export] Instance ConvNeuRed_Algo : ConvNeuRed al := ConvNeuRedAlg.

  Ltac fold_algo_tconv :=
    change ConvTypeAlg with (conv_type (ta := al)) in * ;
    change ConvTypeRedAlg with (conv_type_red (ta := al)) in * ;
    change ConvTermAlg with (conv_term (ta := al)) in * ;
    change ConvTermRedAlg with (conv_term_red (ta := al)) in * ;
    change ConvNeuAlg with (conv_neu (ta := al)) in * ;
    change ConvTypeRedAlg with (conv_type_red (ta := al)) in * ;
    change ConvTermRedAlg with (conv_term_red (ta := al)) in * ;
    change ConvNeuRedAlg with (conv_neu_red (ta := al)) in *.

  Smpl Add fold_algo_tconv : refold.

End AlgorithmicTypedConvData.

Induction principles

Similarly to declarative typing, we need some massaging to turn the output of Scheme to something that fits our purpose, and we also define a function that computes the conclusion of a proof by induction.
Section InductionPrinciples.
  Import AlgorithmicTypingData AlgorithmicTypedConvData.

Scheme
    Minimality for ConvTypeAlg Sort Type with
    Minimality for ConvTypeRedAlg Sort Type with
    Minimality for ConvNeuAlg Sort Type with
    Minimality for ConvNeuRedAlg Sort Type with
    Minimality for ConvTermAlg Sort Type with
    Minimality for ConvTermRedAlg Sort Type.

Scheme
    Minimality for WfTypeAlg Sort Type with
    Minimality for InferAlg Sort Type with
    Minimality for InferRedAlg Sort Type with
    Minimality for CheckAlg Sort Type.

Combined Scheme _AlgoConvInduction from
    ConvTypeAlg_rect_nodep,
    ConvTypeRedAlg_rect_nodep,
    ConvNeuAlg_rect_nodep,
    ConvNeuRedAlg_rect_nodep,
    ConvTermAlg_rect_nodep,
    ConvTermRedAlg_rect_nodep.

Combined Scheme _AlgoTypingInduction from
    WfTypeAlg_rect_nodep,
    InferAlg_rect_nodep,
    InferRedAlg_rect_nodep,
    CheckAlg_rect_nodep.

Let _AlgoConvInductionType :=
  ltac:(let ind := fresh "ind" in
      pose (ind := _AlgoConvInduction);
      refold ;
      let ind_ty := type of ind in
      exact ind_ty).

Let AlgoConvInductionType :=
  ltac: (let ind := eval cbv delta [_AlgoConvInductionType] zeta
    in _AlgoConvInductionType in
    let ind' := polymorphise ind in
  exact ind').

Lemma AlgoConvInduction : AlgoConvInductionType.
Proof.
  intros PTyEq PTyRedEq PNeEq PNeRedEq PTmEq PTmRedEq **.
  pose proof (_AlgoConvInduction PTyEq PTyRedEq PNeEq PNeRedEq PTmEq PTmRedEq) as H.
  destruct H as [?[?[?[?[?]]]]] ; cycle -1.
  1: by_prod_splitter.
  all: assumption.
Qed.

Let _AlgoTypingInductionType :=
  ltac:(let ind := fresh "ind" in
      pose (ind := _AlgoTypingInduction);
      refold ;
      let ind_ty := type of ind in
      exact ind_ty).

Let AlgoTypingInductionType :=
  ltac: (let ind := eval cbv delta [_AlgoTypingInductionType] zeta
    in _AlgoTypingInductionType in
    let ind' := polymorphise ind in
  exact ind').

Lemma AlgoTypingInduction : AlgoTypingInductionType.
Proof.
  intros ? conv PTy PInf PInfRed PCheck **.
  pose proof (_AlgoTypingInduction _ _ PTy PInf PInfRed PCheck) as H.
  destruct H as [?[?[?]]] ; cycle -1.
  1: by_prod_splitter.
  all: assumption.
Qed.

Definition AlgoConvInductionConcl :=
  ltac:(
    let t := eval cbv delta [AlgoConvInductionType] beta in AlgoConvInductionType in
    let t' := remove_steps t in
    exact t').

Definition AlgoTypingInductionConcl :=
  ltac:(
    let t := eval cbv delta [AlgoTypingInductionType] beta in AlgoTypingInductionType in
    let t' := remove_steps t in
    exact t').

Scheme
Minimality for UConvAlg Sort Type with
Minimality for UConvRedAlg Sort Type with
Minimality for UConvNeuAlg Sort Type.

Combined Scheme UAlgoConvInduction from
UConvAlg_rect_nodep,
UConvRedAlg_rect_nodep,
UConvNeuAlg_rect_nodep.

Arguments UAlgoConvInduction PEq PRedEq PNeEq : rename.

Definition UAlgoConvInductionConcl :=
ltac:(
let t := type of UAlgoConvInduction in
let t' := remove_steps t in
exact t').

End InductionPrinciples.

Arguments AlgoConvInductionConcl PTyEq PTyRedEq PNeEq PNeRedEq PTmEq PTmRedEq : rename.
Arguments AlgoConvInduction PTyEq PTyRedEq PNeEq PNeRedEq PTmEq PTmRedEq : rename.
Arguments AlgoTypingInductionConcl {ta conv} PTy PInf PInfRed PCheck : rename.
Arguments AlgoTypingInduction {ta conv} PTy PInf PInfRed PCheck : rename.