MathClasses.theory.ua_packed

Require Import
  canonical_names universal_algebra Program.

Section packed.
  Context (σ: Signature) {V: Type}.

  Inductive Applied: sorts σ Type :=
    | AppliedOp o: Arguments (σ o) Applied (result _ (σ o))
    | AppliedVar: V s, Applied s
  with Arguments: OpType (sorts σ) Type :=
    | NoMoreArguments s: Arguments (ne_list.one s)
    | MoreArguments o' o: Applied o' Arguments o Arguments (ne_list.cons o' o).

  Definition head_arg x y (a: Arguments (ne_list.cons x y)): Applied x :=
    match a with
    | MoreArguments k l m nm
    | NoMoreArguments _False
    end.

  Definition tail_args x y (a: Arguments (ne_list.cons x y)): Arguments y :=
    match a with
    | MoreArguments k l m nn
    | NoMoreArguments _False
    end.

  Context (P: {s}, Applied s Type).
  Arguments P {s} _.

  Section forallArgs.
    Fixpoint forallArgs {o} (a: Arguments o): Type :=
      match a with
      | NoMoreArguments _True
      | MoreArguments _ _ z vprod (P z) (forallArgs v)
      end.

    Definition PofSplit {o}: Arguments o Type :=
      match o with
      | ne_list.one _λ _, unit
      | ne_list.cons x yλ a, prod (P (head_arg x y a)) (forallArgs (tail_args _ _ a))
      end.

    Definition forallSplit `(a: Arguments (ne_list.cons y z)):
      forallArgs a prod (P (head_arg y z a)) (forallArgs (tail_args _ _ a)).
    Proof.
     intro.
     change (PofSplit a).
     destruct a; simpl.
      exact tt.
     assumption.
    Defined.   End forallArgs.

  Context
    (Pop: o x, forallArgs x P (AppliedOp o x))
    (Pvar: v s, P (AppliedVar v s)).

  Fixpoint better_Applied_rect {o} (a: Applied o): P a :=
    match a with
    | AppliedOp x yPop x y (better_args y)
    | AppliedVar x vPvar x v
    end
  with better_args {o} (a: Arguments o): forallArgs a :=
    match a with
    | NoMoreArguments _I
    | MoreArguments _ _ x y(better_Applied_rect x, better_args y)
    end.
End packed.


Fixpoint curry {σ} {V} {o} (a: Applied σ o): Term σ V (ne_list.one o) :=
  match a in (Applied _ s) with
  | AppliedOp op yapply_args y (app_tree σ (Op σ V op))
  | AppliedVar v xVar σ V v x
  end
with apply_args {σ} {V} {o} (a: @Arguments σ V o): op_type (Term0 σ V) o Term0 σ V (result _ o) :=
  match a with
  | NoMoreArguments yid
  | MoreArguments x y u qλ z, apply_args q (z (curry u))
  end.


Fixpoint decode `(t: Term σ V o): Arguments σ o Applied σ (result _ o) :=
  match t with
  | Var x yλ z, AppliedVar σ x y
  | Op xAppliedOp σ x
  | App x y z wλ p, decode z (MoreArguments σ y x (decode w (NoMoreArguments σ _)) p)
  end.


Definition curry_decode `(t: Term σ V o) (a: Arguments σ o):
  curry (decode t a) apply_args a (app_tree σ t).
Proof with simpl in *; try reflexivity.
 induction t...
  dependent destruction a...  rewrite IHt1...
 rewrite IHt2...
Qed.


Definition decode0 `(t: Term0 σ V s): Applied σ s := decode t (NoMoreArguments σ _).

Definition curry_decode0 `(t: Term0 σ V o): curry (decode0 t) t.
Proof. apply (curry_decode t). Qed.