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 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
/* Hierarchy Builder: algebraic hierarchies made easy
This software is released under the terms of the MIT license */
% This file contains some HB specific utilities
accumulate HB/common/utils-synterp.
shorten coq.{ term->gref, subst-fun, safe-dest-app, mk-app, mk-eta, subst-prod }.
pred if-arg-sort i:prop.
if-arg-sort P :- get-option "arg_sort" tt, !, P.
if-arg-sort _.
pred if-MC-compat i:(option gref -> prop).
if-MC-compat P :- get-option "mathcomp" tt, !, P none.
if-MC-compat P :- get-option "mathcomp.axiom" S, !,
std.assert! (coq.locate S GR) "The name passed to the mathcomp.axiom attribute does not exist",
P (some GR).
if-MC-compat _.
pred with-locality i:prop.
with-locality P :-
if (get-option "local" tt) (A = @local!) (A = @global!),
A => P.
pred acc-clause i:scope, i:prop.
acc-clause Scope C :- coq.elpi.accumulate Scope "hb.db" (clause _ _ C).
/* Uncomment and remove HB/common/compat_acc_clauses_*.elpi once requiring coq-elpi >= 1.18.0,
which implies Coq >= 8.17
pred acc-clauses i:scope, i:list prop.
acc-clauses Scope CL :- coq.elpi.accumulate-clauses Scope "hb.db" {std.map CL (c\r\ r = clause _ _ c)}.
*/
% TODO: Should this only be used for gref that are factories? (and check in the first/second branch so?)
% Should we make this an HO predicate, eg "located->gref S L is-factory? GR"
% TODO: rename since this is HB specific and is expected to return a factory
pred located->gref i:string, i:list located, o:gref.
located->gref _ [loc-gref GR|_] GR.
located->gref _ [loc-abbreviation Abbrev|_] GR :- phant-abbrev GR _ Abbrev, !.
located->gref S [loc-abbreviation _|_] _ :- coq.error S "is an abbreviation out of the control of HB".
located->gref S [loc-modpath _|_] _ :- coq.error S "should be a factory, but is a module".
located->gref S [loc-modtypath _|_] _ :- coq.error S "should be a factory, but is a module type".
located->gref S [] _ :- coq.error "Could not locate name" S.
% TODO: generalize/rename when we support parameters
pred argument->gref i:argument, o:gref.
argument->gref (str S) GR :- located->gref S {coq.locate-all S} GR.
argument->gref X _ :- coq.error "Argument" X "is expected to be a string".
pred argument->term i:argument, o:term.
argument->term (str S) (global GR) :- !, argument->gref (str S) GR.
argument->term (trm T) T1 :- !, std.assert-ok! (coq.elaborate-skeleton T _ T1) "not well typed term".
argument->term X _ :- coq.error "Argument" X " is expected to be a term or a string".
pred argument->ty i:argument, o:term.
argument->ty (str S) T1 :- !, argument->gref (str S) GR, std.assert-ok! (coq.elaborate-ty-skeleton (global GR) _ T1) "global reference is not a type".
argument->ty (trm T) T1 :- !, std.assert-ok! (coq.elaborate-ty-skeleton T _ T1) "not well typed type".
argument->ty X _ :- coq.error "Argument" X " is expected to be a type or a string".
pred builder->string i:builder, o:string.
builder->string (builder _ _ _ B) S :- coq.term->string (global B) S.
pred nice-gref->string i:gref, o:string.
nice-gref->string X Mod :-
coq.gref->path X Path,
std.rev Path [Mod1,Mod2|_], !,
Mod is Mod2 ^ "_" ^ Mod1.
nice-gref->string X S :-
coq.term->string (global X) S.
pred gref->modname i:gref, i:int, i:string, o:string.
gref->modname GR NComp Sep ModName :-
coq.gref->path GR Path,
std.rev Path Mods,
std.length Path Len,
if (Len >= NComp) true (coq.error "Not enough enclosing modules for" {coq.gref->string GR}),
std.take NComp Mods L,
std.string.concat Sep {std.rev L} ModName.
pred gref->modname-label i:gref, i:int, i:string, o:string.
gref->modname-label GR NComp Sep ModName :-
coq.gref->path GR Path,
std.rev Path PathRev,
std.length PathRev Len,
if (Len >= NComp) (N = NComp) (N = Len),
std.take N PathRev L,
std.string.concat Sep {std.rev [{coq.gref->id GR}|L]} ModName.
pred string->modpath i:string, o:modpath.
string->modpath S MP :-
std.filter {coq.locate-all S} (l\l = loc-modpath _) L,
L = [loc-modpath MP].
pred gref->modname_short1 i:modpath, i:string, i:list string, o:string.
gref->modname_short1 _ S [] S.
gref->modname_short1 MP "" [X|L] L' :- gref->modname_short1 MP X L L'.
gref->modname_short1 MP S _ S :- string->modpath S MP.
gref->modname_short1 MP S [X|L] S' :-
gref->modname_short1 MP {std.string.concat "." [X,S]} L S'.
% Print shortest qualified identifier of the module containing a gref
% Sep is used as separator
pred gref->modname_short i:gref, i:string, o:string.
gref->modname_short GR Sep IDS :-
coq.gref->path GR Path,
string->modpath {std.string.concat "." Path} MP,
gref->modname_short1 MP "" {std.rev Path} ID,
rex.replace "[.]" Sep ID IDS.
pred avoid-name-collision i:string, o:string.
avoid-name-collision S S1 :-
coq.locate-all S L,
if (std.mem L (loc-gref GR), coq.gref->path GR P, coq.env.current-path P)
(S1 is S ^ "__" ^ {std.any->string {new_int}})
(S1 is S).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function to predicate generic constructions %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pred mk-nil o:list A.
mk-nil [].
pred mk0 i:A, o:A.
mk0 F R :- constant R F [].
pred mk1 i:(A -> B), i:A, o:B.
mk1 F X1 R :- constant R F [X1].
pred mk2 i:(A -> A -> C), i:A, i:A, o:C.
mk2 F X1 X2 R :- constant R F [X1, X2].
pred mk3 i:(A -> A -> A -> D), i:A, i:A, i:A, o:D.
mk3 F X1 X2 X3 R :- constant R F [X1, X2, X3].
pred mk4 i:(A -> A -> A -> A -> E), i:A, i:A, i:A, i:A, o:E.
mk4 F X1 X2 X3 X4 R :- constant R F [X1, X2, X3,X4].
pred mk-fun i:name, i:term, i:(term -> term), o:term.
mk-fun N Ty Body (fun N Ty Body).
% generic argument to pass to w-params
pred ignore i:name, i:term, i:(term -> A), o:A.
ignore _ _ F X :- (pi x y\ F x = F y), X = F (sort prop).
% combining body and type
pred mk-fun-prod i:name, i:term, o:(term -> pair term term), o:pair term term.
mk-fun-prod N Ty (x\ pr (Body x) (Type x)) (pr (fun N Ty Body) (prod N Ty Type)).
pred mk-parameter i:implicit_kind, i:name, i:term, i:(term -> indt-decl), o:indt-decl.
pred mk-parameter i:implicit_kind, i:name, i:term, i:(term -> arity), o:arity.
mk-parameter IK Name X F Decl :- !, Decl = parameter {coq.name->id Name} IK X F.
pred params->holes i:list-w-params A, o:list term.
params->holes (w-params.nil _ _ _) [].
params->holes (w-params.cons _ _ F) [_|PS] :- pi x\ params->holes (F x) PS.
pred fresh-type o:term.
fresh-type Ty :-
Ty = {{Type}},
std.assert-ok! (coq.typecheck-ty Ty _) "impossible".
%%%%%%%%%%%%%%%%%%%%%%
% w-params interface %
%%%%%%%%%%%%%%%%%%%%%%
pred apply-w-params i:w-params A, i:list term, i:term, o:A.
apply-w-params (w-params.cons _ _ PL) [P|PS] T R :- !, apply-w-params (PL P) PS T R.
apply-w-params (w-params.nil _ _ L) [] T R :- !, R = L T.
apply-w-params _ _ _ _ :- coq.error "apply-w-params".
pred w-params.nparams i:w-params A, o:int.
w-params.nparams (w-params.cons _ _ F) N :- pi x\ w-params.nparams (F x) M, N is M + 1.
w-params.nparams (w-params.nil _ _ _) 0.
% [w-params.fold AwP Cons Nil Out] states that Out has shape
% Cons `x_1` T_1 p_1 \ .. \ Nil [p_1 .. p_n] `T` Ty F
% where AwP = w-params.cons `x_1` T_1 p_1 \ ... \ w-params.nil `T` Ty F
pred w-params.fold i:w-params A, i:(name -> term -> (term -> B) -> B -> prop),
i:(list term -> name -> term -> (term -> A) -> B -> prop), o:B.
w-params.fold L Cons Nil Out :- w-params.fold.params L Cons Nil [] Out.
pred w-params.fold.params i:w-params A,
i:(name -> term -> (term -> B) -> B -> prop),
i:(list term -> name -> term -> (term -> A) -> B -> prop),
i:list term, % accumulator
o:B.
w-params.fold.params (w-params.cons ID PTy F) Cons Nil RevPs Out :- !, std.do! [
coq.id->name ID N,
(@pi-decl N PTy p\ w-params.fold.params (F p) Cons Nil [p|RevPs] (Body p)),
Cons N PTy Body Out].
w-params.fold.params (w-params.nil ID TTy F) _ Nil RevParams Out :- !, std.do! [
coq.id->name ID N,
std.rev RevParams Params,
Nil Params N TTy F Out,
].
% [w-params.then AwP Cons Nil Out] states that Out has shape
% Cons `x_1` T_1 p_1 \ .. \ Nil [p_1 .. p_n] `T` Ty t \ Body
% where Pred [p_1 .. p_n] T Body
% and AwP = w-params.cons `x_1` T_1 p_1 \ ... \ w-params.nil `T` Ty F
pred w-params.then i:w-params A,
i:(name -> term -> (term -> C) -> C -> prop),
i:(name -> term -> (term -> B) -> C -> prop),
i:(list term -> term -> A -> B -> prop),
o:C.
w-params.then L Cons Nil Pred Out :-
w-params.fold L Cons (ps\ n\ ty\ f\ out\ sigma Body\
(@pi-decl n ty t\ Pred ps t (f t) (Body t)),
Nil n ty Body out) Out.
pred w-params.map i:w-params A, i:(list term -> term -> A -> B -> prop), o:w-params B.
w-params.map AL F BL :-
w-params.then AL mk-w-params.cons-name mk-w-params.nil-name F BL.
% TODO: make combinators pass id
type mk-w-params.cons-name name -> term -> (term -> w-params A) -> w-params A -> prop.
mk-w-params.cons-name N T F (w-params.cons ID T F):- coq.name->id N ID.
type mk-w-params.nil-name name -> term -> (term -> A) -> w-params A -> prop.
mk-w-params.nil-name N T F (w-params.nil ID T F):- coq.name->id N ID.
% on the fly abstraction
pred bind-nil i:id, i:term, i:term, i:A, o:w-params A.
bind-nil N T X V (w-params.nil N T A) :- V = A X.
pred bind-cons i:id, i:term, i:term, i:w-params A, o:w-params A.
bind-cons N T X V (w-params.cons N T A) :- V = A X.
% Specific to list-w-params
pred list-w-params_list i:list-w-params A, o:list A.
list-w-params_list AwP R :- w-params.then AwP ignore ignore
(p\ t\ x\ std.map x triple_1) R.
pred list-w-params.append i:list-w-params A, i:list-w-params A, o:list-w-params A.
list-w-params.append (w-params.nil N T ML1) (w-params.nil N T ML2) (w-params.nil N T ML) :-
pi x\ std.append (ML1 x) (ML2 x) (ML x).
list-w-params.append (w-params.cons N Ty ML1) (w-params.cons N Ty ML2) (w-params.cons N Ty ML) :-
pi x\ list-w-params.append (ML1 x) (ML2 x) (ML x).
pred list-w-params.rcons i:list-w-params A, i:(list term -> term -> w-args A -> prop), o:list-w-params A.
list-w-params.rcons LwP F R :- list-w-params.rcons.aux LwP F [] R.
pred list-w-params.rcons.aux i:list-w-params A, i:(list term -> term -> w-args A -> prop), i:list term, o:list-w-params A.
list-w-params.rcons.aux (w-params.nil N T ML1) F Acc (w-params.nil N T ML2) :-
pi x\ sigma Last\ F {std.rev Acc} x Last, std.append (ML1 x) [Last] (ML2 x).
list-w-params.rcons.aux (w-params.cons N Ty ML1) F Acc (w-params.cons N Ty ML2) :-
pi x\ list-w-params.rcons.aux (ML1 x) F [x|Acc] (ML2 x).
pred list-w-params.flatten-map
i:list-w-params A,
i:(A -> list-w-params B -> prop),
o:list-w-params B.
list-w-params.flatten-map (w-params.cons N T L) F (w-params.cons N T L1) :-
@pi-parameter N T p\
list-w-params.flatten-map (L p) F (L1 p).
list-w-params.flatten-map (w-params.nil N TTy L) F (w-params.nil N TTy L1) :-
@pi-parameter N TTy t\
list-w-params.flatten-map.aux (L t) F (L1 t).
pred list-w-params.flatten-map.aux
i:list (w-args A), i:(A -> list-w-params B -> prop), o:list (w-args B).
list-w-params.flatten-map.aux [] _ [].
list-w-params.flatten-map.aux [triple M Ps T|L] F Res1 :-
F M MwP,
apply-w-params MwP Ps T ML,
list-w-params.flatten-map.aux L F Res,
std.append ML Res Res1.
% [build-list-w-params TheParams TheType Factories ListWParams]
% Params is a list of pairs (section variable, its type).
% ListWParams has as many w-params.cons as TheParams and the terms
% in Factories are abstracted wrt the first component of TheParams.
pred build-list-w-params i:list (triple id term term), i:term, i:list (w-args A), o: list-w-params A.
build-list-w-params [triple ID P Pty|PS] TheType Factories (w-params.cons ID Pty1 R) :- std.do! [
copy Pty Pty1,
(@pi-parameter ID Pty1 p\ (copy P p :- !) => build-list-w-params PS TheType Factories (R p)),
].
build-list-w-params [] TheType Factories (w-params.nil Name TT1 R) :- std.do! [
std.assert-ok! (coq.typecheck TheType TT) "BUG: TheType does not typecheck",
copy TT TT1,
coq.gref->id {coq.term->gref TheType} Name,
(@pi-parameter Name TT1 t\
(copy TheType t :- !) =>
std.map Factories
(std.map-triple (=) (x\ std.map x (copy-pack-holes TheType t))
(copy-pack-holes TheType t)) (R t)),
].
pred copy-pack-holes i:term, i:term, i:term, o:term.
copy-pack-holes TheType NewType Term Out :- std.do! [
(pi Args NewArgs CSInstance ParamsRev ParamsRevCopy Pack \
(copy (app[global Pack | Args]) (app[global Pack | NewArgs]) :- pack? Pack _,
std.rev Args [CSInstance,TheType|ParamsRev], !,
std.map ParamsRev copy ParamsRevCopy,
std.rev [{{ lib:elpi.hole }},NewType|ParamsRevCopy] NewArgs)) =>
copy Term Out,
].
pred pack? i:gref, o:classname.
pack? (indc K) C :-
coq.env.indc K _ _ _ KTy, prod-last-gref KTy (indt I), % TODO: use new API
class-def (class C (indt I) _).
pred distribute-w-params i:list-w-params A, o:list (one-w-params A).
distribute-w-params (w-params.cons N T F) L :-
pi x\ distribute-w-params (F x) (L1 x), std.map (L1 x) (bind-cons N T x) L.
distribute-w-params (w-params.nil N T F) L :-
pi x\ std.map (F x) (bind-nil N T x) L.
% Specific to one-w-params
pred w-params_1 i:one-w-params A, o:A.
w-params_1 X Y :- w-params.then X ignore ignore (p\ t\ triple_1) Y.
pred disable-id-phant i:term, o:term.
disable-id-phant T T1 :-
(pi fresh fresh1 t v\ copy {{lib:@hb.id lp:t lp:v}} {{lib:@hb.id_disabled lp:t lp:fresh lp:v lp:fresh1}} :- !) =>
(pi fresh fresh1 t v\ copy {{lib:@hb.ignore lp:t lp:v}} {{lib:@hb.ignore_disabled lp:t lp:fresh lp:v lp:fresh1}} :- !) =>
copy T T1.
pred re-enable-id-phant i:term, o:term.
re-enable-id-phant T T1 :-
(pi f1 f2 t v\ copy {{lib:@hb.id_disabled lp:t lp:f1 lp:v lp:f2}} {{lib:@hb.id lp:t lp:v}} :- !) =>
(pi f1 f2 t v\ copy {{lib:@hb.ignore_disabled lp:t lp:f1 lp:v lp:f2}} {{lib:@hb.ignore lp:t lp:v}} :- !) =>
copy T T1.
pred prod-last i:term, o:term.
prod-last (prod N S X) Y :- !, @pi-decl N S x\ prod-last (X x) Y.
prod-last X X :- !.
pred prod-last-gref i:term, o:gref.
prod-last-gref (prod N S X) GR :- !, @pi-decl N S x\ prod-last-gref (X x) GR.
prod-last-gref X GR :- coq.term->gref X GR.
% saturate a type constructor with holes
pred saturate-type-constructor i:term, o:term .
saturate-type-constructor T ET :-
coq.typecheck T TH ok,
coq.count-prods TH N,
coq.mk-app T {coq.mk-n-holes N} ET.
|