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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
From Coq Require Import List String.
Require Import ExtLib.Structures.CoMonad.
Set Implicit Arguments.
Set Strict Implicit.
Inductive type : Type :=
| Self : type
| Inj : Type -> type.
Definition product := list type.
Definition variant := list product.
Section denote.
Variable M : Type.
Definition typeD (t : type) : Type :=
match t with
| Self => M
| Inj t => t
end.
Definition func (T : Type) (v : product) : Type :=
fold_right (fun x acc => typeD x -> acc) T v.
Definition data (v : product) : Type :=
fold_right (fun x acc => typeD x * acc)%type unit v.
Definition matchD (T : Type) (v : variant) : Type :=
fold_right (fun x acc => func T x -> acc)%type T v.
Definition dataD (v : variant) : Type :=
fold_right (fun x acc => data x + acc)%type Empty_set v.
Definition recD (T : Type) (c : Type -> Type) (v : variant) : Type :=
fold_right (fun x acc =>
fold_right (fun x acc =>
match x with
| Inj t => t
| Self => c T
end -> acc) (c T) x -> acc) (M -> T) v.
End denote.
Class Data (T : Type) : Type :=
{ repr : variant
; into : dataD T repr -> T
; outof : T -> forall A, matchD T A repr
; rec : forall c {_ : CoMonad c}, forall A, recD T A c repr
}.
Local Open Scope string_scope.
Global Instance Data_nat : Data nat :=
{ repr := nil :: (Self :: nil) :: nil
; outof := fun x _ z s =>
match x with
| 0 => z
| S n => s n
end
; into := fun d =>
match d with
| inl tt => 0
| inr (inl (n, tt)) => n
| inr (inr x) => match x with end
end
; rec := fun c _ A z s d =>
extract ((fix recur (d : nat) {struct d} : c A :=
match d with
| 0 => z
| S n => s (recur n)
end) d)
}.
Global Instance Data_list {A} : Data (list A) :=
{ repr := (nil) :: (Inj A :: Self :: nil) :: nil
; outof := fun x _ n c =>
match x with
| nil => n
| x :: xs => c x xs
end
; into := fun d =>
match d with
| inl tt => nil
| inr (inl (x, (xs, tt))) => x :: xs
| inr (inr x) => match x with end
end
; rec := fun c _ T n co d =>
extract ((fix recur (ds : list A) {struct ds} : c T :=
match ds with
| nil => n
| d :: ds => co d (recur ds)
end) d)
}.
(** Example of deriving Show from Data **)
Require Import ExtLib.Programming.Show.
Require Import ExtLib.Data.Monads.IdentityMonad.
Require Import ExtLib.Structures.Monads.
Global Instance Comoand_Id : CoMonad id :=
{ extract := fun _ x => x
; extend := fun _ _ x f => x f
}.
(*
Inductive AllResolve (C : Type -> Type) : list type -> Type :=
| AllResolve_nil : AllResolve C nil
| AllResolve_Self : forall ls, AllResolve C ls -> AllResolve C (Self :: ls)
| AllResolve_Inj : forall t ls, C t -> AllResolve C ls -> AllResolve C (Inj t :: ls).
Existing Class AllResolve.
*)
Definition ProductResolve (C : Type -> Type) (r : product) : Type :=
fold_right (fun t acc =>
match t with
| Inj t => C t * acc
| Self => acc
end)%type unit r.
Definition VariantResolve (C : Type -> Type) (r : variant) : Type :=
fold_right (fun p acc => ProductResolve C p * acc)%type unit r.
Existing Class VariantResolve.
Ltac all_resolve :=
simpl VariantResolve; simpl ProductResolve;
repeat match goal with
| |- unit => apply tt
| |- (unit * _)%type => constructor; [ apply tt | ]
| |- (_ * _)%type => constructor
| |- _ => solve [ eauto with typeclass_instances ]
end.
#[global]
Hint Extern 0 (ProductResolve _ _) => all_resolve : typeclass_instances.
#[global]
Hint Extern 0 (VariantResolve _ _) => all_resolve : typeclass_instances.
Definition comma_before (b : bool) (s : showM) : showM :=
if b then
cat (show_exact ",") s
else
s.
Fixpoint show_product (first : bool) (r : list type) {struct r} :
ProductResolve Show r ->
(showM -> showM) ->
(fold_right
(fun (x : type) (acc : Type) =>
match x with
| Self => showM
| Inj t => t
end -> acc) (showM) r).
refine (
match r as r
return
ProductResolve Show r ->
(showM -> showM) ->
(fold_right
(fun (x : type) (acc : Type) =>
match x with
| Self => showM
| Inj t => t
end -> acc) (showM) r)
with
| nil => fun _ f => f empty
| Self :: rs => fun a f s =>
@show_product false rs a (fun s' => f (cat s (comma_before first s')))
| Inj t :: rs => fun a f x => @show_product false rs (snd a) (fun s' => f (cat ((fst a) x) (comma_before first s')))
end); simpl in *.
Defined.
Global Instance Show_data (T : Type) (d : Data T) (AS : VariantResolve Show repr) : Show T :=
{ show :=
(fix recur (repr : variant) : VariantResolve Show repr -> recD T showM id repr -> T -> showM :=
match repr as repr return
VariantResolve Show repr -> recD T showM id repr -> T -> showM
with
| nil => fun _ x => x
| r :: rs => fun a k' =>
recur rs (snd a) (k' (show_product true _ (fst a)
(fun s' => cat (show_exact "-") (cat (show_exact "(") (cat s' (show_exact ")"))))))
end) repr AS (rec (c := id) showM)
}.
Eval compute in
to_string (M := Show_data _ _) (5 :: 6 :: 7 :: nil).
|