├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src ├── context.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "dependent_traits" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "frunk 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "frunk_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 7 | ] 8 | 9 | [[package]] 10 | name = "frunk" 11 | version = "0.2.0" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | dependencies = [ 14 | "frunk_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "frunk_derives 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 16 | ] 17 | 18 | [[package]] 19 | name = "frunk_core" 20 | version = "0.2.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | 23 | [[package]] 24 | name = "frunk_derives" 25 | version = "0.2.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | dependencies = [ 28 | "frunk_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 30 | "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)", 31 | ] 32 | 33 | [[package]] 34 | name = "proc-macro2" 35 | version = "0.2.3" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | dependencies = [ 38 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 39 | ] 40 | 41 | [[package]] 42 | name = "quote" 43 | version = "0.4.2" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | dependencies = [ 46 | "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 47 | ] 48 | 49 | [[package]] 50 | name = "syn" 51 | version = "0.12.15" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | dependencies = [ 54 | "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 55 | "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 56 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 57 | ] 58 | 59 | [[package]] 60 | name = "unicode-xid" 61 | version = "0.1.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | 64 | [metadata] 65 | "checksum frunk 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb8c67434a47b56862411efc6d7879cb2628eee61cfac5607061da314314c44d" 66 | "checksum frunk_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d39f10dd49046071fa1cddff7f9733d97e04c2a22cde6b49f376c4eda95e6c" 67 | "checksum frunk_derives 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "386848569568e19a6a902c0d098baba364ca39b8f5330c7ff515c7af095a4ed0" 68 | "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" 69 | "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" 70 | "checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" 71 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 72 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dependent_traits" 3 | version = "0.1.0" 4 | authors = ["Joshua Yanovski "] 5 | 6 | [dependencies] 7 | frunk = "0.2.0" 8 | frunk_core = "0.2.0" 9 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::ops::Add; 3 | use frunk::{Generic, LabelledGeneric}; 4 | use frunk::hlist::{HCons, HList, HNil, LiftFrom, Selector}; 5 | use frunk::indices::{Here, There}; 6 | use frunk::traits::{IntoReverse}; 7 | // use frunk::prelude::*; 8 | 9 | pub struct Inl { 10 | l: L, 11 | } 12 | 13 | pub struct Inr { 14 | r: R, 15 | } 16 | 17 | pub struct TSome { 18 | t: T, 19 | } 20 | 21 | pub struct TNone; 22 | 23 | pub struct True; 24 | 25 | pub struct False; 26 | 27 | pub trait IAnd { 28 | type Output; 29 | } 30 | 31 | impl IAnd for B { 32 | type Output = False; 33 | } 34 | 35 | impl IAnd for False { 36 | type Output = False; 37 | } 38 | 39 | impl IAnd for True { 40 | type Output = True; 41 | } 42 | 43 | pub trait Equal { 44 | } 45 | 46 | /// EqRefl 47 | impl Equal for T { 48 | } 49 | 50 | /// EqNat : specialized version of equality that returns a boolean instead of succeeding or 51 | /// failing. 52 | pub trait EqNat { 53 | type Conv; 54 | } 55 | 56 | impl EqNat for Here { 57 | type Conv = True; 58 | } 59 | 60 | impl EqNat for There { 61 | type Conv = False; 62 | } 63 | 64 | impl EqNat> for Here { 65 | type Conv = False; 66 | } 67 | 68 | impl EqNat> for There where N1 : EqNat { 69 | type Conv = N1::Conv; 70 | } 71 | 72 | pub trait AtIndex/* : Selector*/ 73 | { 74 | type Output; 75 | } 76 | 77 | impl AtIndex for HCons 78 | { 79 | type Output = Head; 80 | // fn select(&self) -> Selector 81 | // type Selector : Selector<, >; 82 | } 83 | 84 | impl AtIndex> for HCons 85 | where Tail : AtIndex 86 | { 87 | type Output = Tail::Output; 88 | } 89 | 90 | /// Version of AtIndex that returns None on failure. 91 | pub trait AtIndexOpt/* : Selector*/ 92 | { 93 | type Output; 94 | } 95 | 96 | impl AtIndexOpt for HCons { 97 | type Output = TSome; 98 | // fn select(&self) -> Selector 99 | // type Selector : Selector<, >; 100 | } 101 | 102 | impl AtIndexOpt> for HNil { 103 | type Output = TNone; 104 | } 105 | 106 | impl AtIndexOpt> for HCons 107 | where Tail : AtIndexOpt 108 | { 109 | type Output = Tail::Output; 110 | } 111 | 112 | /// Note: Here represents 0 and There K represents K. 113 | pub trait PeanoLen { 114 | type PeanoLen; 115 | } 116 | 117 | impl PeanoLen for HNil { 118 | type PeanoLen = Here; 119 | } 120 | 121 | impl PeanoLen for HCons 122 | where Tail : PeanoLen, 123 | { 124 | type PeanoLen = There; 125 | } 126 | 127 | pub trait IAdd { 128 | type Output; 129 | } 130 | 131 | impl IAdd for M { 132 | type Output = There; 133 | 134 | /* fn add(self, rhs: Here) -> Self::Output { 135 | self 136 | } */ 137 | } 138 | 139 | impl IAdd> for M 140 | where M : IAdd 141 | { 142 | type Output = There<>::Output>; 143 | 144 | /* fn add(self, rhs: There) -> There< as Add>::Output> 145 | //Self::Output 146 | { 147 | // NOTE: Shouldn't really require unsafe (should be able to 148 | // construct it Peano-style as { There : rhs.there.add() }... 149 | // but we don't have access to the module). 150 | unsafe { mem::transmute(self) } 151 | } */ 152 | } 153 | 154 | /// NOTE: For ISub purposes, Here means 0, not 1! 155 | pub trait ISub { 156 | type Output; 157 | } 158 | 159 | impl ISub for M { 160 | type Output = M; 161 | } 162 | 163 | impl ISub> for Here { 164 | type Output = Here; 165 | } 166 | 167 | impl ISub> for There 168 | where M : ISub 169 | { 170 | type Output = >::Output; 171 | } 172 | 173 | /// Lifting 174 | 175 | pub struct ElId; 176 | 177 | /// lift of N, then apply lift Lift 178 | pub struct ElShift { 179 | l: Lift, 180 | n: N, 181 | } 182 | 183 | /// apply Lift to de bruijn > N 184 | pub struct ElLift { 185 | n: N, 186 | l: Lift, 187 | } 188 | 189 | /// Copmose a relocation of magnitude N 190 | pub trait EShiftRec { 191 | type Output; 192 | } 193 | 194 | impl EShiftRec for ElShift 195 | where K: IAdd, 196 | El : EShiftRec<>::Output>, 197 | { 198 | type Output = >::Output>>::Output; 199 | } 200 | 201 | impl EShiftRec for ElId { 202 | type Output = ElShift; 203 | } 204 | 205 | impl EShiftRec for ElLift { 206 | type Output = ElShift, N>; 207 | } 208 | 209 | /// Copmose a relocation of magnitude Pred 210 | pub trait EShift { 211 | type Output; 212 | } 213 | 214 | impl EShift for El { 215 | type Output = El; 216 | } 217 | 218 | impl EShift> for El where El: EShiftRec { 219 | type Output = >::Output; 220 | } 221 | 222 | /// Cross N binders 223 | pub trait ELiftRec { 224 | type Output; 225 | } 226 | 227 | impl ELiftRec for ElId { 228 | type Output = ElId; 229 | } 230 | 231 | impl ELiftRec for ElLift 232 | where K: IAdd, 233 | El : ELiftRec<>::Output>, 234 | { 235 | type Output = >::Output>>::Output; 236 | } 237 | 238 | impl ELiftRec for ElShift { 239 | type Output = ElLift>; 240 | } 241 | 242 | /// Cross Pred binders 243 | pub trait ELiftN { 244 | type Output; 245 | } 246 | 247 | impl ELiftN for El { 248 | type Output = El; 249 | } 250 | 251 | impl ELiftN> for El where El: ELiftRec { 252 | type Output = >::Output; 253 | } 254 | 255 | /// Cross one binder 256 | pub trait ELift { 257 | type Output; 258 | } 259 | 260 | impl ELift for El where El: ELiftN> { 261 | type Output = >>::Output; 262 | } 263 | 264 | /// Relocation of de Bruijn n in an explicit lift ElLift (aux trait, self = n - k) 265 | pub trait RelocRelLift { 266 | type Output; 267 | } 268 | 269 | /// Zero case : n - k ≤ 0 (n ≤ k) 270 | impl RelocRelLift for Here 271 | { 272 | type Output = N; 273 | } 274 | 275 | /// Succ case : n - k = ndiffk (n > k) 276 | impl RelocRelLift for There 277 | where 278 | El: RelocRel, 279 | >::Output: IAdd, 280 | { 281 | type Output = <>::Output as IAdd>::Output; 282 | } 283 | 284 | /// Relocation of de Bruijn n in an explicit lift 285 | pub trait RelocRel { 286 | type Output; 287 | } 288 | 289 | impl RelocRel for ElId { 290 | type Output = N; 291 | } 292 | 293 | impl RelocRel for ElLift 294 | where 295 | There : ISub>, 296 | as ISub>>::Output : RelocRelLift, 297 | { 298 | type Output = < as ISub>>::Output as RelocRelLift>::Output; 299 | } 300 | 301 | impl RelocRel for ElShift 302 | where 303 | N : IAdd, 304 | El : RelocRel<>::Output>, 305 | { 306 | type Output = >::Output>>::Output; 307 | } 308 | 309 | /// Substitutions 310 | 311 | /// ESID(n) = %n END bounded identity 312 | pub struct EsId { 313 | /// NOTE: n = pred N 314 | n: N, 315 | } 316 | 317 | /// CONS(t,S) = (S.t) parallel substitution 318 | pub struct EsCons { 319 | t: T, 320 | s: S, 321 | } 322 | 323 | /// SHIFT(n,S) = (^n o S) terms in S are relocated with n vars 324 | pub struct EsShift { 325 | n: N, 326 | s: S, 327 | } 328 | 329 | /// LIFT(n,S) = (%n S) stands for ((^n o S).n...1) 330 | pub struct EsLift { 331 | n: N, 332 | s: S, 333 | } 334 | 335 | pub trait SubsCons { 336 | type Output; 337 | } 338 | 339 | impl SubsCons for S { 340 | type Output = EsCons; 341 | } 342 | 343 | pub trait SubsLiftN2 { 344 | type Output; 345 | } 346 | 347 | /// bounded identity lifted extends by p 348 | /// 349 | /// Here + N = N; There P + N = P + N; thn add 1, so it 350 | /// amounts to just adding P. 351 | impl SubsLiftN2 for EsId

where P : IAdd { 352 | type Output = EsId<

>::Output>; 353 | } 354 | 355 | impl SubsLiftN2 for EsLift where P : IAdd { 356 | type Output = EsLift<

)> 1140 | where 1141 | There : ISub>, 1142 | FFlex> : WhdLift< as ISub>>::Output>, 1143 | { 1144 | type Output = > as WhdLift< as ISub>>::Output>>::Output; 1145 | } 1146 | 1147 | /// Optimization: do not enclose variables in a closure. 1148 | /// Makes variable access much faster. 1149 | /// E is the environment. 1150 | pub trait MkClos { 1151 | type Output; 1152 | } 1153 | 1154 | impl MkClos for Rel 1155 | where 1156 | E : ExpandRel, 1157 | >::Output : ClosRel, 1158 | { 1159 | type Output = <>::Output as ClosRel>::Output; 1160 | } 1161 | 1162 | impl MkClos for Sort { 1163 | type Output = FVal>; 1164 | } 1165 | 1166 | impl MkClos for Lambda { 1167 | type Output = FCbn, E>; 1168 | } 1169 | 1170 | impl MkClos for Prod { 1171 | type Output = FCbn, E>; 1172 | } 1173 | 1174 | impl MkClos for App { 1175 | type Output = FCbn, E>; 1176 | } 1177 | 1178 | /// The inverse of mk_clos: move Self back to constr under Lfts lifting environment. 1179 | pub trait ToConstr { 1180 | type Output; 1181 | } 1182 | 1183 | /// Values in normal form just get lifted to the corresponding Constr. 1184 | impl ToConstr for FVal where C : ExLiftN { 1185 | type Output = >::Output; 1186 | } 1187 | 1188 | /// FFlex values also just get lifted to the corresponding Constr (the difference mostly 1189 | /// matters for conversion, which wants to compare RelKeys for equality without 1190 | /// considering the lifting environment because it knows that if they are equal unlifted 1191 | /// their bodies will also be equal; while for interior substitutions, that's not the case 1192 | /// since they are not shared between the two terms, and they must be exactly identical). 1193 | impl ToConstr for FFlex where C : ExLiftN { 1194 | type Output = >::Output; 1195 | } 1196 | 1197 | impl ToConstr for FCbn, Env> 1198 | where 1199 | F : MkClos, 1200 | >::Output : ToConstr, 1201 | A : MkClos, 1202 | >::Output : ToConstr, 1203 | { 1204 | type Output = App<<>::Output as ToConstr>::Output, 1205 | <>::Output as ToConstr>::Output>; 1206 | } 1207 | 1208 | impl ToConstr for FCbn, Env> 1209 | where 1210 | T : MkClos, 1211 | >::Output : ToConstr, 1212 | Env : SubsLift, 1213 | B : MkClos<::Output>, 1214 | Lfts : ELift, 1215 | ::Output>>::Output : ToConstr<::Output>, 1216 | { 1217 | type Output = Lambda<<>::Output as ToConstr>::Output, 1218 | <::Output>>::Output as 1219 | ToConstr<::Output>>::Output>; 1220 | } 1221 | 1222 | impl ToConstr for FCbn, Env> 1223 | where 1224 | T : MkClos, 1225 | >::Output : ToConstr, 1226 | Env : SubsLift, 1227 | C : MkClos<::Output>, 1228 | Lfts : ELift, 1229 | ::Output>>::Output : 1230 | ToConstr<::Output>, 1231 | { 1232 | type Output = Prod<<>::Output as ToConstr>::Output, 1233 | <::Output>>::Output as 1234 | ToConstr<::Output>>::Output>; 1235 | } 1236 | 1237 | /// For an empty stack, just apply ToConstr to the value at the stack head. 1238 | impl ToConstr for FStk 1239 | where 1240 | V : ToConstr, 1241 | { 1242 | type Output = >::Output; 1243 | } 1244 | 1245 | /// For an app (reversed) stack, first run Stk on F, then apply the result to A. 1246 | impl ToConstr for FStk, Stk>> 1247 | where 1248 | FStk : ToConstr, 1249 | A : ToConstr, 1250 | { 1251 | type Output = App< as ToConstr>::Output, >::Output>; 1252 | } 1253 | 1254 | /// For a shift (reversed) stack, shift Lfts by K, then run Stk on V with the resulting Lfts. 1255 | impl ToConstr for FStk, Stk>> 1256 | where 1257 | Lfts : EShift>, 1258 | FStk : ToConstr<>>::Output>, 1259 | { 1260 | type Output = as ToConstr<>>::Output>>::Output; 1261 | } 1262 | 1263 | /// fapp_stack transforms a value and a stack into the reversed stack applied to the value, 1264 | /// generally for use in to_constr. M is the value and Self is the stack. 1265 | pub trait FAppStack { 1266 | type Output; 1267 | } 1268 | 1269 | /// For now, FAppStack just reverses and doesn't do anything else (like unlocking updates). 1270 | impl FAppStack for Stk { 1271 | type Output = FStk::Output>; 1272 | } 1273 | 1274 | /// Eta expansion: add a reference to implicit surrounding lambda at end of stack 1275 | pub trait EtaExpandStack { 1276 | type Output; 1277 | } 1278 | 1279 | /// We append rather than use explicit induction. 1280 | impl EtaExpandStack for Stk 1281 | where 1282 | Stk : Add, ZApp>>]>, 1283 | { 1284 | type Output = Stk::Output; 1285 | } 1286 | 1287 | /// A machine that inspects the head of a term until it finds an 1288 | /// atom or a subterm that may produce a redex (abstraction, 1289 | /// constructor, cofix, letin, constant), or a neutral term (product, 1290 | /// inductive) 1291 | /// 1292 | /// Self is Info, term is M, stack is Stk. Returned head is Head, returned stack is Stack. 1293 | /// 1294 | /// For FStk terms with reversed stacks, we just move elements from the reversed stack to the 1295 | /// non-reversed one. 1296 | pub trait Knh { 1297 | type Head; 1298 | type Stack; 1299 | } 1300 | 1301 | /// For FStk terms with an empty stack, we just run knh on the head. 1302 | impl Knh, Stk> for Info where Info : Knh { 1303 | type Head = >::Head; 1304 | type Stack = >::Stack; 1305 | } 1306 | 1307 | /// For FStk terms with a zshift k, we shift the current stack by k and rerun with 1308 | /// the stack tail. 1309 | impl Knh, A>>, Stk> for Info 1310 | where 1311 | Stk : StkShift, 1312 | Info : Knh, >::Output>, 1313 | { 1314 | type Head = , >::Output>>::Head; 1315 | type Stack = , >::Output>>::Stack; 1316 | } 1317 | 1318 | /// For FStk terms with a zapp b, we append b to the current stack and rerun with 1319 | /// the stack tail. 1320 | impl Knh, A>>, Stk> for Info 1321 | where 1322 | Stk : WhdAppendStack, 1323 | Info : Knh, >::Output>, 1324 | { 1325 | type Head = , >::Output>>::Head; 1326 | type Stack = , >::Output>>::Stack; 1327 | } 1328 | 1329 | /// For FCbn terms, we run knht. 1330 | impl Knh, Stk> for Info where Info : Knht { 1331 | type Head = >::Head; 1332 | type Stack = >::Stack; 1333 | } 1334 | 1335 | /// For FVal terms, we return. 1336 | impl Knh, Stk> for Info { 1337 | type Head = FVal; 1338 | type Stack = Stk; 1339 | } 1340 | 1341 | /// For FFlex terms, we return. 1342 | impl Knh, Stk> for Info { 1343 | type Head = FFlex; 1344 | type Stack = Stk; 1345 | } 1346 | 1347 | /// The same as knh for pure terms. 1348 | /// 1349 | /// Self is Info, env is E, term is M, stack is Stk. 1350 | /// Returned head is Head, returned stack is Stack. 1351 | pub trait Knht { 1352 | type Head; 1353 | type Stack; 1354 | } 1355 | 1356 | impl Knht, Stk> for Info 1357 | where 1358 | B : MkClos, 1359 | Stk : WhdAppendStack<>::Output>, 1360 | Info : Knht>::Output>>::Output>, 1361 | { 1362 | type Head = 1363 | >::Output>>::Output>>::Head; 1364 | type Stack = 1365 | >::Output>>::Output>>::Stack; 1366 | } 1367 | 1368 | /// NOTE: This is the only Knht that can yield a FStk; as a result, we can assume 1369 | /// that we don't see an FStk in knr (since we call knh, which takes care of FStks). 1370 | impl Knht, Stk> for Info 1371 | where 1372 | /* E : ExpandRel, 1373 | >::Output : ClosRel, 1374 | Info : Knh<<>::Output as ClosRel>::Output, Stk>, */ 1375 | Rel : MkClos, 1376 | Info : Knh< as MkClos>::Output, Stk>, 1377 | { 1378 | /* type Head = >::Output as ClosRel>::Output, Stk>>::Head; 1379 | type Stack = >::Output as ClosRel>::Output, Stk>>::Stack; */ 1380 | type Head = as MkClos>::Output, Stk>>::Head; 1381 | type Stack = as MkClos>::Output, Stk>>::Stack; 1382 | } 1383 | 1384 | impl 1385 | Knht, Stk> for Info where Lambda : MkClos { 1386 | type Head = as MkClos>::Output; 1387 | type Stack = Stk; 1388 | } 1389 | 1390 | impl Knht, Stk> for Info where Prod : MkClos { 1391 | type Head = as MkClos>::Output; 1392 | type Stack = Stk; 1393 | } 1394 | 1395 | impl Knht, Stk> for Info where Sort : MkClos { 1396 | type Head = as MkClos>::Output; 1397 | type Stack = Stk; 1398 | } 1399 | 1400 | /// Decides whether to continue expanding a FFlex or not based on the result of RefValueCache. 1401 | /// 1402 | /// Self is Info, initial FFlex value is C, RefValueCache result is V, stack is Stk. 1403 | /// Returned head is Head, returned stack is Stack. 1404 | pub trait KnrFlex2 { 1405 | type Head; 1406 | type Stack; 1407 | } 1408 | 1409 | /// If RefValueCache is None, return FFlex and Stk unchanged. 1410 | impl KnrFlex2 for Info { 1411 | type Head = FFlex; 1412 | type Stack = Stk; 1413 | } 1414 | 1415 | /// If RefValueCache is TSome, run kni on V. 1416 | impl KnrFlex2, Stk> for Info where Info : Kni { 1417 | type Head = >::Head; 1418 | type Stack = >::Stack; 1419 | } 1420 | 1421 | /// Knr for FFlex, where Delta is the delta flag for Self. 1422 | pub trait KnrFlex { 1423 | type Head; 1424 | type Stack; 1425 | } 1426 | 1427 | /// For a FFlex C, we look up C in our local environment and kni (if Delta). 1428 | impl KnrFlex for Info 1429 | where 1430 | Info : RefValueCache, 1431 | Info : KnrFlex2>::Output, Stk>, 1432 | { 1433 | type Head = >::Output, Stk>>::Head; 1434 | type Stack = >::Output, Stk>>::Stack; 1435 | } 1436 | 1437 | /// For a FFlex C, we return the FFlex (if !Delta). 1438 | impl KnrFlex for Info { 1439 | type Head = FFlex; 1440 | type Stack = Stk; 1441 | } 1442 | 1443 | /// Computes a weak head normal form from the result of knh. 1444 | /// Self is Info, term is M, stack is Stk. 1445 | /// Returned head is Head, returned stack is Stack. 1446 | pub trait Knr { 1447 | type Head; 1448 | type Stack; 1449 | } 1450 | 1451 | /// For a FVal C, we return C and the stack unchanged. 1452 | impl Knr, Stk> for Info { 1453 | type Head = FVal; 1454 | type Stack = Stk; 1455 | } 1456 | 1457 | /// For a FFlex C, we look up C in our local environment and kni (if Delta). 1458 | impl Knr, Stk> for Info 1459 | where 1460 | Info : KnrFlex::Flags as Reds>::Delta>, 1461 | { 1462 | type Head = ::Delta>>::Head; 1463 | type Stack = ::Delta>>::Stack; 1464 | } 1465 | 1466 | /// For an empty stack with a FCbn Lambda, we return the Cbn and stack unaltered. 1467 | impl Knr, E>, HNil> for Info { 1468 | type Head = FCbn, E>; 1469 | type Stack = HNil; 1470 | } 1471 | 1472 | /// For a shift stack with a FCbn Lambda, we apply the shift to the Cbn environment. 1473 | impl Knr, E>, HCons, S>> for Info 1474 | where 1475 | E : SubsShft, 1476 | Info : Knr, >::Output>, S>, 1477 | { 1478 | type Head = , >::Output>, S>>::Head; 1479 | type Stack = , >::Output>, S>>::Stack; 1480 | } 1481 | 1482 | /// For an app stack with a FCbn Lambda, we cons the app to the Cbn environment and knit. 1483 | impl Knr, E>, HCons, S>> for Info 1484 | where 1485 | E : SubsCons, 1486 | Info : Knit<>::Output, B, S>, 1487 | { 1488 | type Head = >::Output, B, S>>::Head; 1489 | type Stack = >::Output, B, S>>::Stack; 1490 | } 1491 | 1492 | impl Knr, E>, Stk> for Info { 1493 | type Head = FCbn, E>; 1494 | type Stack = Stk; 1495 | } 1496 | 1497 | /// Computes the weak head normal form of a term 1498 | pub trait Kni { 1499 | type Head; 1500 | type Stack; 1501 | } 1502 | 1503 | impl Kni for Info 1504 | where 1505 | Info : Knh, 1506 | Info : Knr<>::Head, >::Stack>, 1507 | { 1508 | type Head = >::Head, >::Stack>>::Head; 1509 | type Stack = >::Head, >::Stack>>::Stack; 1510 | } 1511 | 1512 | /// Computes the weak head normal form of a pure term. 1513 | pub trait Knit { 1514 | type Head; 1515 | type Stack; 1516 | } 1517 | 1518 | impl Knit for Info 1519 | where 1520 | Info : Knht, 1521 | Info : Knr<>::Head, >::Stack>, 1522 | { 1523 | type Head = 1524 | >::Head, >::Stack>>::Head; 1525 | type Stack = 1526 | >::Head, >::Stack>>::Stack; 1527 | } 1528 | 1529 | pub trait Kh { 1530 | type Output; 1531 | } 1532 | 1533 | impl Kh for Info 1534 | where 1535 | Info : Kni, 1536 | >::Stack : FAppStack<>::Head>, 1537 | { 1538 | type Output = <>::Stack as FAppStack<>::Head>>::Output; 1539 | } 1540 | 1541 | /// Weak reduction 1542 | pub trait WhdVal { 1543 | type Output; 1544 | } 1545 | 1546 | impl WhdVal for Info 1547 | where 1548 | Info : Kh, 1549 | >::Output : ToConstr, 1550 | { 1551 | type Output = <>::Output as ToConstr>::Output; 1552 | } 1553 | 1554 | pub trait Inject { 1555 | type Output; 1556 | } 1557 | 1558 | impl Inject for T where T : MkClos> { 1559 | type Output = T::Output; 1560 | } 1561 | 1562 | pub trait WhdStack { 1563 | type Head; 1564 | type Stack; 1565 | } 1566 | 1567 | impl WhdStack for Info where Info : Kni, 1568 | { 1569 | type Head = >::Head; 1570 | type Stack = >::Stack; 1571 | } 1572 | 1573 | pub trait CreateClosInfos { 1574 | type Info; 1575 | } 1576 | 1577 | pub struct ClosInfos { 1578 | flags: Flags, 1579 | rels: Rels, 1580 | } 1581 | 1582 | impl Infos for ClosInfos { 1583 | type Flags = Flags; 1584 | type Rels = Rels; 1585 | } 1586 | 1587 | impl CreateClosInfos for Env { 1588 | type Info = ClosInfos; 1589 | } 1590 | 1591 | /// Compute the lift to be performed on a term placed in a given stack (Self) 1592 | pub trait ElStack { 1593 | type Output; 1594 | } 1595 | 1596 | impl ElStack for HNil { 1597 | type Output = El; 1598 | } 1599 | 1600 | impl ElStack for HCons, Stk> 1601 | where 1602 | El : EShift>, // NOTE: If we switch to allow shifts of 0, switch to N 1603 | Stk : ElStack<>>::Output>, 1604 | { 1605 | type Output = >>::Output>>::Output; 1606 | } 1607 | 1608 | impl ElStack for HCons, Stk> where Stk : ElStack { 1609 | type Output = >::Output; 1610 | } 1611 | 1612 | /// Modified version of pure_stack that avoids creating a new kind of stack. 1613 | /// 1614 | /// Consumes a *reversed* stack Self. This allows the lifts to be consumed in 1615 | /// reverse, which means that the Lfts returned by PureStack represent all the 1616 | /// Lfts by which the current stack tail would be lifted. Because the order of 1617 | /// conversion during compare_stack doesn't matter, our going in reverse shouldn't 1618 | /// be a big problem. Note that the output Stack is in the same order as the input 1619 | /// stack (reversed). 1620 | pub trait PureStack { 1621 | type Lfts; 1622 | type Stack; 1623 | } 1624 | 1625 | impl PureStack for HCons, Stk> 1626 | where 1627 | Lfts : EShift>, // NOTE: If we switch to allow shifts of 0, switch to N 1628 | Stk : PureStack<>>::Output>, 1629 | { 1630 | type Lfts = >>::Output>>::Lfts; 1631 | type Stack = >>::Output>>::Stack; 1632 | } 1633 | 1634 | impl PureStack for HNil { 1635 | type Lfts = Lfts; 1636 | type Stack = Self; 1637 | } 1638 | 1639 | impl PureStack for HCons, Stk> { 1640 | type Lfts = Lfts; 1641 | type Stack = Self; 1642 | } 1643 | 1644 | /// Reduction functions 1645 | 1646 | /// Macro for generating boilerplate trait impls for Whd (first list is of constrs that are already 1647 | /// in whd for the current reduction strategy, second list is for constrs that are not and need to 1648 | /// be reduced). 1649 | /// TODO: Find a way to generalize this sort of macro. 1650 | macro_rules! impl_whd { 1651 | ($whd_trait:ident, $red_flags:ty, 1652 | [$(([$($whnf_param:ident),*], $whnf_constr:ty)),*], 1653 | [$(([$($red_param:ident),*], $red_constr:ty)),*] 1654 | ) => { 1655 | pub trait $whd_trait { 1656 | type Output; 1657 | } 1658 | $( 1659 | impl<$($whnf_param, )*Ctx> $whd_trait for $whnf_constr { 1660 | type Output = $whnf_constr; 1661 | } 1662 | )* 1663 | $( 1664 | /* impl<$($red_param, )*Ctx> $whd_trait for $red_constr { 1665 | type Output = $red_constr; 1666 | } */ 1667 | impl<$($red_param, )*Ctx> $whd_trait for $red_constr 1668 | where 1669 | Ctx : CreateClosInfos<$red_flags>, 1670 | $red_constr : Inject, 1671 | >::Info : 1672 | WhdVal<<$red_constr as Inject>::Output>, 1673 | { 1674 | type Output = <>::Info 1675 | as WhdVal<<$red_constr as Inject>::Output>>::Output; 1676 | } 1677 | )* 1678 | } 1679 | } 1680 | 1681 | impl_whd!(WhdAll, BetaDeltaIota, 1682 | [([S], Sort), 1683 | ([T, C], Prod), 1684 | ([T, B], Lambda)], 1685 | [([N], Rel), 1686 | ([F, A], App)]); 1687 | 1688 | /// Conversion 1689 | 1690 | /// Conversion utility functions 1691 | 1692 | /// Self is Infos; only needs to deal with pure stack members. 1693 | pub trait CompareStacks { 1694 | type Conv; 1695 | } 1696 | 1697 | /// Empty stacks are equal. 1698 | impl CompareStacks for Info { 1699 | type Conv = True; 1700 | } 1701 | 1702 | /// App stacks are equal if the terms are convertible. 1703 | impl CompareStacks, Stk1>, 1704 | Lft2, HCons, Stk2>> for Info 1705 | where 1706 | Info : CCnv, 1707 | Stk1 : PureStack, 1708 | Stk2 : PureStack, 1709 | // NOTE: Might be nice to make this run only if member equality succeeds. 1710 | Info : CompareStacks<>::Lfts, 1711 | >::Stack, 1712 | >::Lfts, 1713 | >::Stack>, 1714 | >::Conv : 1715 | IAnd<>::Lfts, 1716 | >::Stack, 1717 | >::Lfts, 1718 | >::Stack>>::Conv>, 1719 | { 1720 | type Conv = 1721 | <>::Conv as 1722 | IAnd<>::Lfts, 1723 | >::Stack, 1724 | >::Lfts, 1725 | >::Stack>>::Conv>>::Output; 1726 | } 1727 | 1728 | /// Nonempty Stk1 ≠ empty Stk2 1729 | impl CompareStacks, Lft2, HNil> for Info { 1730 | type Conv = False; 1731 | } 1732 | 1733 | /// Empty Stk1 ≠ nonempty Stk2 1734 | impl CompareStacks> for Info { 1735 | type Conv = False; 1736 | } 1737 | 1738 | /// Convertibility of sorts 1739 | 1740 | pub struct PbConv; 1741 | 1742 | pub struct PbCumul; 1743 | 1744 | /// S0 ~ S1 using conversion strategy Self 1745 | pub trait SortCmp { 1746 | type Conv; 1747 | } 1748 | 1749 | /// Syntactically equal sorts are equal for any conversion strategy. 1750 | impl SortCmp for Pb { 1751 | type Conv = True; 1752 | } 1753 | 1754 | /// Set is convertible with Type where conversion is cumulative. 1755 | impl SortCmp for PbCumul { 1756 | type Conv = True; 1757 | } 1758 | 1759 | /// Set is not convertible with Type where conversion is exact. 1760 | impl SortCmp for PbConv { 1761 | type Conv = False; 1762 | } 1763 | 1764 | /// Type is never convertible with Set. 1765 | impl SortCmp for Pb { 1766 | type Conv = False; 1767 | } 1768 | 1769 | /// Conversion between [lft1]term1 and [lft2]term2 1770 | pub trait CCnv { 1771 | type Conv; 1772 | } 1773 | 1774 | /// Conversion between [lft1](stk1 ⊢ v1) and [lft2](stk2 ⊢ v2) 1775 | /// 1776 | /// NOTE: Expects both sides to already be in WHNF! 1777 | pub trait EqAppr { 1778 | type Conv; 1779 | } 1780 | 1781 | pub trait ConvertStacks { 1782 | type Conv; 1783 | } 1784 | 1785 | impl CCnv for Info 1786 | where 1787 | Info : WhdStack, 1788 | Info : WhdStack, 1789 | Info : EqAppr>::Head, 1790 | >::Stack, 1791 | Lfts2, >::Head, 1792 | >::Stack>, 1793 | { 1794 | type Conv = Info::Conv; 1795 | } 1796 | 1797 | /// Conversion between [lft1](stk1 ⊢ v1 = ref_value_cache fl1', fl1 = FFlex fl1') and 1798 | /// [lft2](stk2 ⊢ v2 = ref_value_cache fl2', fl2 = FFlex fl2') and 1799 | /// either v1 ≠ v2 or stk1 ≠ stk2 1800 | /// 1801 | /// (can also be used in general to reduce one side or the other after computation). 1802 | pub trait EqApprFlex3 { 1803 | type Conv; 1804 | } 1805 | 1806 | /// Both None : N1 and N2 must either not be syntactically equal, or their stacks must 1807 | /// are not convertible, so the terms cannot be convertible. 1808 | impl 1809 | EqApprFlex3 for Info { 1810 | type Conv = False; 1811 | } 1812 | 1813 | /// Fl1 = Some, Fl2 = None : reduce V1 and recompare. 1814 | impl 1815 | EqApprFlex3, Stk1, Lfts2, Fl2, TNone, Stk2> for Info 1816 | where 1817 | Info : WhdStack, 1818 | Info : EqAppr>::Head, 1819 | >::Stack, 1820 | Lfts2, Fl2, Stk2>, 1821 | { 1822 | type Conv = 1823 | >::Head, 1824 | >::Stack, 1825 | Lfts2, Fl2, Stk2>>::Conv; 1826 | } 1827 | 1828 | /// Fl1 = None, Fl2 = Some : reduce V2 and recompare. 1829 | impl 1830 | EqApprFlex3, Stk2> for Info 1831 | where 1832 | Info : WhdStack, 1833 | Info : EqAppr>::Head, 1835 | >::Stack> 1836 | { 1837 | type Conv = 1838 | >::Head, 1840 | >::Stack>>::Conv; 1841 | } 1842 | 1843 | /// Both Some : reduce both sides and recompare. 1844 | impl 1845 | EqApprFlex3, Stk1, Lfts2, Fl2, TSome, Stk2> for Info 1846 | where 1847 | Info : WhdStack, 1848 | Info : WhdStack, 1849 | Info : EqAppr>::Head, 1850 | >::Stack, 1851 | Lfts2, >::Head, 1852 | >::Stack>, 1853 | { 1854 | type Conv = 1855 | >::Head, 1856 | >::Stack, 1857 | Lfts2, >::Head, 1858 | >::Stack>>::Conv; 1859 | } 1860 | 1861 | /// Conversion between [lft1](stk1 ⊢ FFlex fl1) and 1862 | /// [lft2](stk2 ⊢ FFlex fl2) where 1863 | /// (fl1 == fl2) == True and 1864 | /// (stk1 == stk2) == StkEq and 1865 | /// 1866 | /// (can also be used in general to reduce one side or the other after computation). 1867 | pub trait EqApprFlex2 { 1868 | type Conv; 1869 | } 1870 | 1871 | /// Not equal : Stk1 ≠ Stk2, so try looking up Fl1 and Fl2 before resuming reduction. 1872 | impl 1873 | EqApprFlex2 for Info 1874 | where 1875 | Info : RefValueCache, 1876 | Info : RefValueCache, 1877 | Info : EqApprFlex3, >::Output, Stk1, 1878 | Lfts2, FFlex, >::Output, Stk2>, 1879 | { 1880 | type Conv = 1881 | , >::Output, Stk1, 1882 | Lfts2, FFlex, >::Output, Stk2>>::Conv; 1883 | } 1884 | 1885 | /// Both equal : Stk1 = Stk2, so the terms are convertible. 1886 | impl 1887 | EqApprFlex2 for Info { 1888 | type Conv = True; 1889 | } 1890 | 1891 | /// Conversion between [lft1](stk1 ⊢ FFlex fl1) and 1892 | /// [lft2](stk2 ⊢ FFlex fl2) where 1893 | /// (fl1 == fl2) == FlEq 1894 | /// 1895 | /// (can also be used in general to reduce one side or the other after computation). 1896 | pub trait EqApprFlex { 1897 | type Conv; 1898 | } 1899 | 1900 | /// Not equal : Fl1 and Fl2 are not syntactically equal, so try looking them up before resuming 1901 | /// reduction. 1902 | impl 1903 | EqApprFlex for Info 1904 | where 1905 | Info : RefValueCache, 1906 | Info : RefValueCache, 1907 | Info : EqApprFlex3, >::Output, Stk1, 1908 | Lfts2, FFlex, >::Output, Stk2>, 1909 | { 1910 | type Conv = 1911 | , >::Output, Stk1, 1912 | Lfts2, FFlex, >::Output, Stk2>>::Conv; 1913 | } 1914 | 1915 | /// Both equal : Fl1 and Fl2 are syntactically equal, so try converting their stacks. 1916 | impl 1917 | EqApprFlex for Info 1918 | where 1919 | Info : ConvertStacks, 1920 | Info : EqApprFlex2>::Conv> 1922 | { 1923 | type Conv = >::Conv>>::Conv; 1926 | } 1927 | 1928 | /// Macro for generating boilerplate trait impls for EqAppr where the two sides are never 1929 | /// convertible. 1930 | /// TODO: Find a way to generalize this sort of macro. 1931 | macro_rules! impl_eqappr_false { 1932 | ([$($param1:ident),*], $constr1:ty, [$($param2:ident),*], $constr2:ty) => { 1933 | impl 1934 | EqAppr for Info 1935 | { 1936 | type Conv = False; 1937 | } 1938 | } 1939 | } 1940 | 1941 | /// NOTE: The pure version of Stk1 and Stk2 is necessarily empty if the term typechecked 1942 | impl 1943 | EqAppr>, Stk1, Lfts2, FVal>, Stk2> for Info 1944 | where CvPb : SortCmp 1945 | { 1946 | type Conv = CvPb::Conv; 1947 | } 1948 | 1949 | /// All the remaining terms that can't compare to Sorts: Rel, Lambda, Prod. 1950 | impl_eqappr_false!([S], FVal>, [N], FVal>); 1951 | impl_eqappr_false!([S], FVal>, [T, B, E], FCbn, E>); 1952 | impl_eqappr_false!([S], FVal>, [T, C, E], FCbn, E>); 1953 | impl_eqappr_false!([N], FVal>, [S], FVal>); 1954 | impl_eqappr_false!([T, B, E], FCbn, E>, [S], FVal>); 1955 | impl_eqappr_false!([T, C, E], FCbn, E>, [S], FVal>); 1956 | 1957 | /// Normal rels (which have no associated body) compare equal only if they are equal in this lift 1958 | /// environment and their stacks are equal. 1959 | impl 1960 | EqAppr>, Stk1, Lfts2, FVal>, Stk2> for Info 1961 | where 1962 | Stk1 : ElStack, 1963 | Stk2 : ElStack, 1964 | >::Output : RelocRel, 1965 | >::Output : RelocRel, 1966 | <>::Output as RelocRel>::Output : 1967 | EqNat<<>::Output as RelocRel>::Output>, 1968 | // NOTE: Should probably make this run only if EqNat succeeds. 1969 | Info : ConvertStacks, 1970 | <<>::Output as RelocRel>::Output as 1971 | EqNat<<>::Output as RelocRel>::Output>>::Conv : 1972 | IAnd<>::Conv>, 1973 | { 1974 | type Conv = 1975 | <<<>::Output as RelocRel>::Output as 1976 | EqNat<<>::Output as RelocRel>::Output>>::Conv as 1977 | IAnd<>::Conv>>::Output; 1978 | } 1979 | 1980 | /// All the remaining terms that can't compare to Rels: Prod. 1981 | impl_eqappr_false!([N], FVal>, [T, C, E], FCbn, E>); 1982 | impl_eqappr_false!([T, C, E], FCbn, E>, [N], FVal>); 1983 | 1984 | /// Flexes compare equal only if they are equal (no lift is needed, since we can evaluate them 1985 | /// in the shared environment) and their stacks are equal, or they evaluate to equal terms. 1986 | /// When we add constants, we want to try reducing one side at a time, e.g. the first before 1987 | /// the second, according to some oracle order, and then rechecking, in case we get lucky and 1988 | /// arrive at a syntactic equality. 1989 | /// 1990 | /// Note: currently, no terms are considered incomparable to Flex. 1991 | impl 1992 | EqAppr>, Stk1, Lfts2, FFlex>, Stk2> for Info 1993 | where 1994 | N1 : EqNat, 1995 | Info : EqApprFlex, Stk1, Lfts2, Rel, Stk2, 1996 | >::Conv>, 1997 | { 1998 | type Conv = 1999 | , Stk1, Lfts2, Rel, Stk2, 2000 | >::Conv>>::Conv; 2001 | } 2002 | 2003 | 2004 | /// Lambdas compare equal when their types compare equal and their bodies compare equal in the 2005 | /// lifted environment. 2006 | /// 2007 | /// NOTE: Stk1 and Stk2 should actually be *empty* for well-typed terms; we try enforcing it here. 2008 | /// This means we don't need to run ElStack on Lfts1 or Lfts2 either. 2009 | impl 2010 | EqAppr, E1>, /*Stk1*/HNil, 2011 | Lfts2, FCbn, E2>, /*Stk2*/HNil> for Info 2012 | where 2013 | // Types are convertible (exact conversion) 2014 | T1 : MkClos, 2015 | T2 : MkClos, 2016 | Info : CCnv>::Output, >::Output>, 2017 | // Bodies are convertible (in lifted environments with exact conversion) 2018 | Lfts1 : ELift, 2019 | Lfts2 : ELift, 2020 | E1 : SubsLift, 2021 | E2 : SubsLift, 2022 | B1 : MkClos<::Output>, 2023 | B2 : MkClos<::Output>, 2024 | // NOTE: Might be nice to make this run only if type equality succeeds. 2025 | Info : CCnv::Output, ::Output, 2026 | ::Output>>::Output, 2027 | ::Output>>::Output>, 2028 | >::Output, >::Output>>::Conv : 2031 | IAnd<::Output, ::Output, 2032 | ::Output>>::Output, 2033 | ::Output>>::Output>>::Conv>, 2034 | { 2035 | type Conv = 2036 | <>::Output, >::Output>>::Conv as 2039 | IAnd<::Output, ::Output, 2040 | ::Output>>::Output, 2041 | ::Output>>::Output>>::Conv>>::Output; 2042 | } 2043 | 2044 | /// All the remaining terms that can't compare to Lambda: Prod. 2045 | impl_eqappr_false!([T1, B1, E1], FCbn, E1>, [T2, C2, E2], FCbn, E2>); 2046 | impl_eqappr_false!([T1, C1, E1], FCbn, E1>, [T2, B2, E2], FCbn, E2>); 2047 | 2048 | /// Products compare equal when their types compare equal and their bodies compare equal in the 2049 | /// lifted environment. 2050 | /// 2051 | /// NOTE: Stk1 and Stk2 should satisfy is_empty for well-typed terms, but it may not actually be 2052 | /// empty. Thus we need to run ElStack on Lfts1 and Lfts2 (also, we might be throwing away some 2053 | /// things on the stack? Should investigate further). 2054 | /// 2055 | /// NOTE: The types of the Cs are converted exactly but the dependent types are converted according 2056 | /// to the current strategy. 2057 | /// 2058 | /// Note: currently, no remaining terms are considered incomparable to Prod. 2059 | impl 2060 | EqAppr, E1>, Stk1, 2061 | Lfts2, FCbn, E2>, Stk2> for Info 2062 | where 2063 | // Extract lifts from stacks. 2064 | Stk1 : ElStack, 2065 | Stk2 : ElStack, 2066 | // Types are convertible (exact conversion) 2067 | T1 : MkClos, 2068 | T2 : MkClos, 2069 | Info : CCnv>::Output, >::Output, 2070 | >::Output, >::Output>, 2071 | // Bodies are convertible (in lifted environments with current conversion strategy); 2072 | // Luo's system 2073 | >::Output : ELift, 2074 | >::Output : ELift, 2075 | E1 : SubsLift, 2076 | E2 : SubsLift, 2077 | C1 : MkClos<::Output>, 2078 | C2 : MkClos<::Output>, 2079 | // NOTE: Might be nice to make this run only if type equality succeeds. 2080 | Info : CCnv>::Output as ELift>::Output, 2081 | <>::Output as ELift>::Output, 2082 | ::Output>>::Output, 2083 | ::Output>>::Output>, 2084 | >::Output, >::Output, 2086 | >::Output, >::Output>>::Conv : 2087 | IAnd<>::Output as ELift>::Output, 2088 | <>::Output as ELift>::Output, 2089 | ::Output>>::Output, 2090 | ::Output>>::Output>>::Conv>, 2091 | 2092 | { 2093 | type Conv = 2094 | <>::Output, >::Output, 2096 | >::Output, >::Output>>::Conv as 2097 | IAnd<>::Output as ELift>::Output, 2098 | <>::Output as ELift>::Output, 2099 | ::Output>>::Output, 2100 | ::Output>>::Output>>::Conv>>::Output; 2101 | } 2102 | 2103 | /// Macro for generating boilerplate trait impls for EqAppr with FLambda only on the left side. 2104 | /// TODO: Find a way to generalize this sort of macro. 2105 | macro_rules! impl_eqappr_flambda_lhs { 2106 | ([$($param:ident),*], $constr:ty) => { 2107 | /// Eta-expansion on the fly 2108 | /// 2109 | /// NOTE: Stk1 should be *empty* here for well-typed terms; we try enforcing it here. 2110 | impl 2111 | EqAppr, E1>, HNil, Lfts2, $constr, Stk2> for Info 2112 | where 2113 | // Body of Lambda is convertible with eta expanded non-Lambda term (in lifted 2114 | // environments with exact conversion). 2115 | // 2116 | // NOTE: We don't try to convert the type parameter here, which may or may not lead 2117 | // to problems down the line. TODO: see if we can get this to show up in the 2118 | // Coq kernel. 2119 | Lfts1 : ELift, 2120 | Lfts2 : ELift, 2121 | E1 : SubsLift, 2122 | B1 : MkClos<::Output>, 2123 | Stk2 : EtaExpandStack, 2124 | // We call EqApprFlex just to reduce both sides before recursing. 2125 | Info : EqApprFlex3::Output, (), 2126 | TSome<::Output>>::Output>, 2127 | HNil, 2128 | ::Output, (), 2129 | TSome<$constr>, ::Output>, 2130 | { 2131 | type Conv = 2132 | ::Output, (), 2133 | TSome<::Output>>::Output>, 2134 | HNil, 2135 | ::Output, (), 2136 | TSome<$constr>, ::Output>>::Conv; 2137 | } 2138 | } 2139 | } 2140 | 2141 | // NOTE: Sorts do not have product types so we should never try to convert them with Lambdas. 2142 | // impl_eqappr_flambda_lhs!([S], FVal>); 2143 | impl_eqappr_flambda_lhs!([N], FVal>); 2144 | impl_eqappr_flambda_lhs!([Fl], FFlex); 2145 | // NOTE: Products do not have product types so we should never try to convert them with Lambdas. 2146 | // impl_eqappr_flambda_lhs!([T, C, E], FCbn, E>); 2147 | 2148 | /// Macro for generating boilerplate trait impls for EqAppr with FLambda only on the right side. 2149 | /// TODO: Find a way to generalize this sort of macro. 2150 | macro_rules! impl_eqappr_flambda_rhs { 2151 | ([$($param:ident),*], $constr:ty) => { 2152 | /// Eta-expansion on the fly 2153 | /// 2154 | /// NOTE: Stk2 should be *empty* here for well-typed terms; we try enforcing it here. 2155 | impl 2156 | EqAppr, E2>, HNil> for Info 2157 | where 2158 | // Body of Lambda is convertible with eta expanded non-Lambda term (in lifted 2159 | // environments with exact conversion). 2160 | // 2161 | // NOTE: We don't try to convert the type parameter here, which may or may not lead 2162 | // to problems down the line. TODO: see if we can get this to show up in the 2163 | // Coq kernel. 2164 | Lfts1 : ELift, 2165 | Lfts2 : ELift, 2166 | E2 : SubsLift, 2167 | B2 : MkClos<::Output>, 2168 | Stk1 : EtaExpandStack, 2169 | // We call EqApprFlex just to reduce both sides before recursing. 2170 | Info : EqApprFlex3::Output, (), 2171 | TSome<$constr>, ::Output, 2172 | ::Output, (), 2173 | TSome<::Output>>::Output>, 2174 | HNil>, 2175 | { 2176 | type Conv = 2177 | ::Output, (), 2178 | TSome<$constr>, ::Output, 2179 | ::Output, (), 2180 | TSome<::Output>>::Output>, 2181 | HNil>>::Conv; 2182 | } 2183 | } 2184 | } 2185 | 2186 | // NOTE: Sorts do not have product types so we should never try to convert them with Lambdas. 2187 | // impl_eqappr_flambda_rhs!([S], FVal>); 2188 | impl_eqappr_flambda_rhs!([N], FVal>); 2189 | impl_eqappr_flambda_rhs!([Fl], FFlex); 2190 | // NOTE: Products do not have product types so we should never try to convert them with Lambdas. 2191 | // impl_eqappr_flambda_rhs!([T, C, E], FCbn, E>); 2192 | 2193 | /// Macro for generating boilerplate trait impls for EqAppr with FFlex only on the left side. 2194 | /// TODO: Find a way to generalize this sort of macro. 2195 | macro_rules! impl_eqappr_fflex_lhs { 2196 | ([$($param:ident),*], $constr:ty) => { 2197 | impl 2198 | EqAppr, Stk1, Lfts2, $constr, Stk2> for Info 2199 | where 2200 | Info : RefValueCache, 2201 | Info : EqApprFlex3, >::Output, Stk1, 2203 | Lfts2, $constr, TNone, Stk2>, 2204 | { 2205 | type Conv = 2206 | , >::Output, Stk1, 2208 | Lfts2, $constr, TNone, Stk2>>::Conv; 2209 | } 2210 | } 2211 | } 2212 | 2213 | impl_eqappr_fflex_lhs!([S], FVal>); 2214 | impl_eqappr_fflex_lhs!([N], FVal>); 2215 | // NOTE: Lambdas come first in Coq's reduction. 2216 | // impl_eqappr_fflex_lhs!([T, C, E], FCbn, E>); 2217 | impl_eqappr_fflex_lhs!([T, C, E], FCbn, E>); 2218 | 2219 | /// Macro for generating boilerplate trait impls for EqAppr with FFlex only on the right side. 2220 | /// TODO: Find a way to generalize this sort of macro. 2221 | macro_rules! impl_eqappr_fflex_rhs { 2222 | ([$($param:ident),*], $constr:ty) => { 2223 | impl 2224 | EqAppr, Stk2> for Info 2225 | where 2226 | Info : RefValueCache, 2227 | Info : EqApprFlex3, >::Output, Stk2>, 2230 | { 2231 | type Conv = 2232 | , 2234 | >::Output, Stk2>>::Conv; 2235 | } 2236 | } 2237 | } 2238 | 2239 | impl_eqappr_fflex_rhs!([S], FVal>); 2240 | impl_eqappr_fflex_rhs!([N], FVal>); 2241 | // NOTE: Lambdas come first in Coq's reduction. 2242 | // impl_eqappr_fflex_rhs!([T, C, E], FCbn, E>); 2243 | impl_eqappr_fflex_rhs!([T, C, E], FCbn, E>); 2244 | 2245 | /* /// Temporary conversion hack: exact equality after weak head reduction. 2246 | impl 2247 | EqAppr for Info 2248 | where 2249 | V1 : Equal, 2250 | Stk1 : Equal, 2251 | { 2252 | } */ 2253 | 2254 | impl ConvertStacks for Info 2255 | where 2256 | // Reverse stacks to satisfy PureStack precondition 2257 | Stk1 : IntoReverse, 2258 | Stk2 : IntoReverse, 2259 | // Purify both stacks to staisfy CompareStacks precondition 2260 | ::Output : PureStack, 2261 | ::Output : PureStack, 2262 | // Compare both stacks. 2263 | Info : CompareStacks<<::Output as PureStack>::Lfts, 2264 | <::Output as PureStack>::Stack, 2265 | <::Output as PureStack>::Lfts, 2266 | <::Output as PureStack>::Stack> 2267 | { 2268 | type Conv = 2269 | ::Output as PureStack>::Lfts, 2270 | <::Output as PureStack>::Stack, 2271 | <::Output as PureStack>::Lfts, 2272 | <::Output as PureStack>::Stack>>::Conv; 2273 | } 2274 | 2275 | pub trait FConv { 2276 | } 2277 | 2278 | impl FConv for Ctx 2279 | where 2280 | Ctx : CreateClosInfos, 2281 | T1 : Inject, 2282 | T2 : Inject, 2283 | >::Info : CCnv, 2285 | { 2286 | } 2287 | 2288 | /// Self is the type context. 2289 | pub trait ConvLeq/*: JudgeOfSort*/ { 2290 | } 2291 | 2292 | impl ConvLeq for Ctx 2293 | where 2294 | // T1 : Execute, 2295 | // T2 : Execute, 2296 | Ctx : FConv, 2297 | { 2298 | } 2299 | 2300 | pub trait JudgeOfSort { 2301 | // type Sort; 2302 | } 2303 | 2304 | /* impl JudgeOfSort for Sort { 2305 | type Sort = S; 2306 | } */ 2307 | impl JudgeOfSort for Set {} 2308 | 2309 | impl JudgeOfSort for Type {} 2310 | 2311 | pub trait TypeJudgment { 2312 | type Sort /*where Sort*/ : JudgeOfSort; 2313 | } 2314 | 2315 | impl TypeJudgment for Sort 2316 | where S : JudgeOfSort, 2317 | { 2318 | type Sort = S; 2319 | 2320 | /* ty.whd_all(self, iter::empty())?; // Mutates in-place. 2321 | match *ty { 2322 | Constr::Sort(ref s) => Ok((self, s)), 2323 | _ => Err(Box::new(CaseError::Type(error_not_type(self, (c.clone(), ty_.clone()))))), 2324 | } */ 2325 | } 2326 | 2327 | pub trait JudgeOfType { 2328 | type Sort /*where Sort*/ : JudgeOfSort; 2329 | } 2330 | 2331 | impl JudgeOfType for Sort { 2332 | type Sort = Type; 2333 | } 2334 | 2335 | pub trait JudgeOfApply { 2336 | type Type; 2337 | } 2338 | 2339 | impl JudgeOfApply for Prod 2340 | where 2341 | Ctx : ConvLeq, 2342 | C : Subst1, 2343 | /* 2344 | 2345 | match typ { 2346 | Constr::Prod(o) => { 2347 | let (_, ref c1, ref c2) = *o; 2348 | if let Err(e) = self.conv_leq(hj, c1, iter::empty()) { 2349 | return Err(CaseError::from_conv(e, move || 2350 | // NOTE: n + 1 is always in-bounds for usize because argjv.len() must 2351 | // be isize::MAX or smaller (provided pointers are at least 1 byte and 2352 | // argjv is backed by a vector, which is the case here). 2353 | error_cant_apply_bad_type( 2354 | self, (n + 1, (*c1).clone(), hj.clone()), 2355 | (f.clone(), funj.clone()), 2356 | argjv.map( |&(h, ref hj)| (h.clone(), hj.clone())) 2357 | .collect()))) 2358 | } 2359 | typ = c2.subst1(h)?; 2360 | }, 2361 | _ => return Err(Box::new(CaseError::Type( 2362 | error_cant_apply_not_functional( 2363 | self, (f.clone(), funj.clone()), 2364 | argjv.map( |&(h, ref hj)| (h.clone(), hj.clone())).collect()))) 2365 | ), 2366 | } 2367 | */ 2368 | { 2369 | type Type = C::Output; 2370 | } 2371 | 2372 | pub trait SortOfProduct 2373 | where 2374 | /*Sort*/T : JudgeOfSort, 2375 | /*Sort*/C : JudgeOfSort, 2376 | { 2377 | type Sort /*where Sort*/ : JudgeOfSort; 2378 | } 2379 | 2380 | impl SortOfProduct for Ctx { 2381 | type Sort = Type; 2382 | } 2383 | 2384 | impl SortOfProduct for Ctx { 2385 | type Sort = Type; 2386 | } 2387 | 2388 | impl SortOfProduct for Ctx { 2389 | type Sort = Type; 2390 | } 2391 | 2392 | impl SortOfProduct for Ctx { 2393 | type Sort = Set; 2394 | } 2395 | /* 2396 | fn sort_of_product<'a>(&self, domsort: &Sort, rangsort: &'a Sort) -> IdxResult> { 2397 | Ok(match (domsort, rangsort) { 2398 | // Product rule (s, Prop, Prop) 2399 | (_, &Sort::Prop(SortContents::Null)) => Cow::Borrowed(rangsort), 2400 | // Product rule (Prop/Set,Set,Set) 2401 | (&Sort::Prop(_), &Sort::Prop(SortContents::Pos)) => Cow::Borrowed(rangsort), 2402 | // Product rule (Type,Set,?) 2403 | (&Sort::Type(ref u1), &Sort::Prop(SortContents::Pos)) => 2404 | if let Engagement::ImpredicativeSet = *self.stratification.engagement() { 2405 | // Rule is (Type,Set,Set) in the Set-impredicative calculus 2406 | Cow::Borrowed(rangsort) 2407 | } else { 2408 | // Rule is (Type_i,Set,Type_i) in the Set-predicative calculus 2409 | // FIXME: Because we mutate the first argument in-place, we swap the argument 2410 | // order here compared to the OCaml implementation. Hopefully, this doesn't 2411 | // affect the result of sup in any significant way (it *shouldn't*, I think), 2412 | // but we need to double check this. 2413 | let mut u0 = Univ::type0(&self.globals.univ_hcons_tbl); 2414 | u0.sup(u1, &self.globals.univ_hcons_tbl)?; 2415 | Cow::Owned(Sort::Type(u0)) 2416 | }, 2417 | // Product rule (Set,Type_i,Type_i) 2418 | (&Sort::Prop(SortContents::Pos), &Sort::Type(ref u2)) => { 2419 | let mut u0 = Univ::type0(&self.globals.univ_hcons_tbl); 2420 | u0.sup(u2, &self.globals.univ_hcons_tbl)?; 2421 | Cow::Owned(Sort::Type(u0)) 2422 | }, 2423 | // Product rule (Prop,Type_i,Type_i) 2424 | (&Sort::Prop(SortContents::Null), &Sort::Type(_)) => Cow::Borrowed(rangsort), 2425 | // Product rule (Type_i,Type_i,Type_i) 2426 | (&Sort::Type(ref u1), &Sort::Type(ref u2)) => { 2427 | // NOTE: The way sup (really merge_univs) is currently written, this clone is 2428 | // somewhat extraneous... 2429 | // TODO: see if merge_univs can be fixed to exploit mutability of one of its 2430 | // arguments. 2431 | let mut u1 = u1.clone(); 2432 | u1.sup(u2, &self.globals.univ_hcons_tbl)?; 2433 | Cow::Owned(Sort::Type(u1)) 2434 | }, 2435 | }) 2436 | * 2437 | */ 2438 | 2439 | /* pub trait DecomposeApp : Context 2440 | { 2441 | type F; 2442 | type Args : HList; 2443 | } 2444 | 2445 | /// Note: list is reversed! 2446 | impl DecomposeApp, Args> for Ctx 2447 | where Ctx : DecomposeApp> 2448 | { 2449 | type Args = >>::Args; 2450 | } 2451 | 2452 | impl DecomposeApp, Args> for Ctx 2453 | { 2454 | type Args = >>::Args; 2455 | } */ 2456 | 2457 | pub trait Execute { 2458 | type Type : /*JudgeOfSort + *//*?Sized*/;// : JudgeOfSort + ?Sized; 2459 | } 2460 | 2461 | impl Execute for Sort 2462 | where 2463 | Self : JudgeOfType, 2464 | // Ctx : Execute, 2465 | // Ctx::Subs : AtIndex, 2466 | // >::Output: RDecl, 2467 | // <>::Output as RDecl>::Type : Lift, 2468 | // <<>::Output as RDecl>::Type as Lift>::Output : JudgeOfSort 2469 | // Ty : UnLift, 2470 | { 2471 | type Type = Sort<::Sort>; 2472 | } 2473 | 2474 | impl Execute for Rel 2475 | where 2476 | // Ctx : Execute, 2477 | Ctx::Subs : AtIndex, 2478 | >::Output: RDecl, 2479 | <>::Output as RDecl>::Type : Lift, 2480 | // <<>::Output as RDecl>::Type as Lift>::Output : JudgeOfSort/**/ 2481 | { 2482 | type Type = <<>::Output as RDecl>::Type as Lift>::Output; 2483 | } 2484 | 2485 | impl Execute for App 2486 | where 2487 | // Ctx : DecomposeApp>, 2488 | A : Execute, 2489 | F : Execute, 2490 | F::Type : WhdAll, 2491 | >::Output : JudgeOfApply, 2492 | // >::Output : TypeJudgment, 2493 | // >::Type : WhdAll, 2494 | /* 2495 | fn judge_of_apply<'a, 'e, I>(&'e mut self, f: &Constr, funj: &Constr, argjv: I 2496 | ) -> CaseResult<'e, 'b, 'g, (&'e mut Self, Constr)> 2497 | where 2498 | I: Clone + Iterator, 2499 | { 2500 | let mut typ = funj.clone(); // We remember the old funj for error reporting purposes. 2501 | for (n, &(h, ref hj)) in argjv.clone().enumerate() { 2502 | typ.whd_all(self, iter::empty())?; // Mutates in-place 2503 | ... 2504 | } 2505 | return Ok((self, typ)) 2506 | } 2507 | */ 2508 | { 2509 | type Type = <>::Output as JudgeOfApply>::Type; 2510 | /* 2511 | let mut o = o; 2512 | // Initialize with the arguments we know we need for sure. 2513 | // TODO: It's possible we could avoid allocating a Vec for args *or* jl with a 2514 | // custom iterator... as it is, we end up taking up space anyway since we remember 2515 | // args in order to ease error reporting (though it would not be hard to fix just 2516 | // that problem). 2517 | let mut jl = Vec::new(); 2518 | let mut env = self; 2519 | loop { 2520 | let (ref f, ref args) = **o; 2521 | // Take advantage of knowledge of the length to add capacity more quickly 2522 | // than we otherwise might. 2523 | jl.reserve(args.len()); 2524 | // We process the arguments in reverse order. This allows us to avoid 2525 | // allocating an intermediate vector to store appended arguments if it turns 2526 | // out that f is itself an application. In theory, this should be perfectly 2527 | // fine, since for this part of the check all the terms in the application can 2528 | // be checked in parallel. In practice, since this evaluates in a different 2529 | // order from the current Coq implementation, it won't always error in the same 2530 | // way, which might be annoying for fuzzing purposes, but since this is the 2531 | // checker it shouldn't normally matter for end users. 2532 | for arg in args.iter().rev() { 2533 | let env_ = env; 2534 | let (env_, j) = env_.execute(arg)?; 2535 | env = env_; 2536 | jl.push((arg, j)); 2537 | } 2538 | // If f is an App, continue to evaluate the arguments of the application in f. 2539 | if let Constr::App(ref o_) = *f { o = o_ } else { break } 2540 | } 2541 | // Now we've evaluated all the arguments to some non-application Constr (note that 2542 | // jl is reversed, hence the re-reversals below!) so it's time to type f. 2543 | let f = &(**o).0; 2544 | let j = match *f { 2545 | Constr::Ind(ref o) => // Sort-polymorphism of inductive types 2546 | env.judge_of_inductive_knowing_parameters(o, jl.iter() 2547 | .map(|j| &j.1).rev())?, 2548 | Constr::Const(ref o) => { // Sort-polymorphism of constant 2549 | let env_ = env; 2550 | let (env_, j) = 2551 | env_.judge_of_constant_knowing_parameters(o, jl.iter().map(|j| &j.1) 2552 | .rev())?; 2553 | env = env_; j 2554 | }, 2555 | _ => { // No sort-polymorphism 2556 | let env_ = env; let (env_, j) = env_.execute(f)?; env = env_; Cow::Owned(j) 2557 | }, 2558 | }; 2559 | env.judge_of_apply(f, &j, jl.iter().rev()) 2560 | */ 2561 | } 2562 | 2563 | impl Execute for Lambda 2564 | where 2565 | T : ExecuteType, 2566 | C : Execute, /*::Subs/*>::Repr*/>>, 2567 | /*let (ref name, ref c1, ref c2) = **o; 2568 | let mut ty = Constr::Rel(0); // dummy 2569 | let (env, _) = self.execute_type(c1, &mut ty)?; 2570 | env.push_rel(RDecl::LocalAssum(name.clone(), c1.clone())); 2571 | let (env, j_) = env.execute(c2)?; 2572 | // Make sure to unwind the rel_context on success. 2573 | // Note that we currently don't pop the rel if there was an error, even if it 2574 | // wasn't a TypeError that consumed the env. 2575 | if let Some(RDecl::LocalAssum(name, c1)) = env.rel_context.pop() { 2576 | Ok((env, Constr::Prod(ORef(Arc::from((name, c1, j_)))))) 2577 | } else { unreachable!("env should be unchanged if the execute was successful.") }*/ 2578 | { 2579 | type Type = Prod, /*::Subs/*>::Repr*/>>>::Type>; 2580 | } 2581 | 2582 | impl Execute for Prod 2583 | where 2584 | T : ExecuteType, 2585 | C : ExecuteType, /*::Subs/*>::Repr*/>>, 2586 | Ctx : SortOfProduct<>::Sort, 2587 | , ::Subs>>>::Sort>, 2588 | { 2589 | type Type = Sort<>::Sort, 2590 | , /*::Subs/*>::Repr*/>>>::Sort>>::Sort>; 2591 | } 2592 | /*Constr::Prod(ref o) => { 2593 | let (ref name, ref c1, ref c2) = **o; 2594 | let mut ty = Constr::Rel(0); // dummy 2595 | let (env, varj) = self.execute_type(c1, &mut ty)?; 2596 | env.push_rel(RDecl::LocalAssum(name.clone(), c1.clone())); 2597 | let mut ty = Constr::Rel(0); // dummy 2598 | let (env, varj_) = env.execute_type(c2, &mut ty)?; 2599 | // Make sure to unwind the rel_context on success. 2600 | // Note that we currently don't pop the rel if there was an error, even if it 2601 | // wasn't a TypeError that consumed the env. 2602 | env.rel_context.pop(); 2603 | let sort = env.sort_of_product(varj, varj_)?.into_owned(); 2604 | Ok((env, Constr::Sort(ORef(Arc::from(sort))))) 2605 | },*/ 2606 | 2607 | pub trait ExecuteType 2608 | // Self: Execute, 2609 | // Self::Type : JudgeOfSort/**/, 2610 | { 2611 | type Sort /*where Sort*/ : JudgeOfSort; 2612 | } 2613 | 2614 | impl ExecuteType for Term 2615 | where 2616 | Term : Execute, 2617 | Term::Type : WhdAll, 2618 | >::Output : TypeJudgment, 2619 | /*Term : Execute, 2620 | Term::Type : JudgeOfSort/**/,*/ 2621 | { 2622 | type Sort = <>::Output as TypeJudgment>::Sort;//::Sort; 2623 | } 2624 | 2625 | #[cfg(test)] 2626 | mod test { 2627 | use frunk::hlist::{HCons, HNil, LiftFrom, Selector}; 2628 | use frunk::indices::{Here, There}; 2629 | use super::*; 2630 | 2631 | #[derive(Generic, LabelledGeneric)] 2632 | struct MyContext { 2633 | subs: Subs, 2634 | } 2635 | 2636 | impl RawContext for MyContext { 2637 | type Subs = Subs; 2638 | } 2639 | 2640 | impl MyContext { 2641 | fn my_judge_sort(/*, x : X*/) 2642 | where 2643 | Ty : ExecuteType, 2644 | S : JudgeOfSort, 2645 | //Ty : ExecuteType, 2646 | //Ty: TypeJudgment, 2647 | { 2648 | } 2649 | 2650 | fn my_judge_type(/*, x : X*/) 2651 | where 2652 | X : Execute, 2653 | Ty : ExecuteType, 2654 | S : JudgeOfSort, 2655 | //Ty: JudgeOfSort/**/, 2656 | { 2657 | } 2658 | 2659 | fn my_whd() 2660 | where 2661 | E : Execute, 2662 | E::Type : ExecuteType, 2663 | E : WhdAll, 2664 | { 2665 | } 2666 | 2667 | fn my_conv() 2668 | where 2669 | E1 : Execute, 2670 | E2 : Execute, 2671 | // E1::Type : ExecuteType, 2672 | // E2::Type : ExecuteType, 2673 | Self : ConvLeq, 2674 | Self : ConvLeq, 2675 | { 2676 | } 2677 | 2678 | fn my_conv_sort() 2679 | where 2680 | // E1 : Execute, 2681 | // E2 : Execute, 2682 | // E1::Type : ExecuteType, 2683 | // E2::Type : ExecuteType, 2684 | // Self : ConvLeq, 2685 | Self : ConvLeq, 2686 | { 2687 | } 2688 | } 2689 | 2690 | #[test] 2691 | fn judge_simple_rel() { 2692 | type Ctx = MyContext, Sort>, 2694 | Assum>, 2695 | Assum, Prod>, Rel>>>>, 2696 | Assum> 2697 | ]>; 2698 | // let my_context = MyContext { subs : hlist![(), Assum { ty: Sort { sort: Set } }] }; 2699 | // let rel = Rel { index: Here }; 2700 | // my_context.my_judge::, Sort>(); 2701 | Ctx::my_judge_sort::, Type>(); 2702 | Ctx::my_judge_sort::, Type>(); 2703 | Ctx::my_judge_sort::>, Set>(); 2704 | Ctx::my_judge_type::>>, Prod, Prod>>>>, Rel>>>, Type>(); 2705 | // Nice: ∀ (X : Set) (Y : ∀ (_ : X), X), Y : Set 2706 | MyContext::, Rel>>>, Assum>]>:: 2707 | my_judge_type::, Prod>, Rel>>>, Set>(); 2708 | // Beelow should error: roughly equivalent to forall (X : Set) (Y : X), Y, which (in Coq) 2709 | // errors with `the term "Y" has type "X" which should be Set, Prop or Type.` 2710 | // Ctx::my_judge_type::, Rel>, Sort, Set>(); 2711 | Ctx::my_judge_sort::, Rel>, Type>(); 2712 | Ctx::my_judge_sort::, Rel>, Type>(); 2713 | Ctx::my_judge_sort::, Sort>, Type>(); 2714 | Ctx::my_judge_sort::>, Sort>, Type>(); 2715 | Ctx::my_judge_sort::, Rel>>, Type>(); 2716 | Ctx::my_judge_type::>, Rel>, Prod>, Rel>>>, Set>(); 2717 | // Below should error: would require universe larger than Type. 2718 | // Ctx::my_judge_type::>, Sort>, Prod>, Sort>, Type>(); 2719 | Ctx::my_judge_type::>, Rel>>>, Prod>, Sort>, Type>(); 2720 | // Note: below test basically a duplicate 2721 | MyContext::>, Assum>]>:: 2722 | my_judge_type::>, Rel>>>, Prod>, Sort>, Type>(); 2723 | MyContext::>, Assum>]>:: 2724 | my_judge_type::>, Rel>>, Prod>, Rel>>>, Set>(); 2725 | Ctx::my_judge_type::, Rel>, Rel>>, Sort, Type>(); 2726 | Ctx::my_judge_type::, Lambda, Rel>>, Prod, Prod, Rel>>>, Type>(); 2727 | Ctx::my_judge_type::, Lambda, Rel>>, Rel>>, 2728 | Prod>, Rel>>>, 2729 | Set>(); 2730 | // Note: below test is basically a duplicate 2731 | MyContext::>, Assum>]>:: 2732 | my_judge_type::, Lambda, Rel>>, Rel>>, 2733 | Prod>, Rel>>>, 2734 | Set>(); 2735 | MyContext::>, Assum>]>:: 2736 | my_judge_type::, Lambda, Rel>>, Rel>>, Rel>, 2737 | Rel>, 2738 | Set>(); 2739 | MyContext::>]>:: 2740 | my_judge_type::, Rel>, Rel>, Rel>, 2741 | Prod, Rel>, Rel>, App, Rel>, Rel>>>, 2742 | Set>(); 2743 | MyContext::>]>:: 2744 | my_judge_type::, Rel>, Rel>, 2745 | App, Rel>, 2746 | Rel>>, 2747 | Rel>, 2748 | Rel>>, 2749 | Prod, Rel>, Rel>, App, Rel>, Rel>>>, 2750 | Set>(); 2751 | /*MyContext::, Rel>, Sort>, Sort>]>:: 2752 | my_judge_type::, /*Sort*/Rel>, Type>();*/ 2753 | MyContext::>, Decl, Rel>, Sort>, Sort>]>:: 2754 | my_judge_type::, /*Sort*/Rel>, Type>(); 2755 | Ctx::my_judge_type::, 2756 | Lambda, Rel>>, 2757 | App, Rel>>>>, 2758 | Prod, 2759 | Prod, Rel>>, 2760 | Rel>>>, 2761 | Type>(); 2762 | Ctx::my_judge_type::, 2763 | Lambda, Rel>, 2764 | App, Rel>>>>, 2765 | Prod, 2766 | Prod, Rel>, 2767 | Rel>>>, 2768 | Type>(); 2769 | // Below should error: would require a universe larger than Type. 2770 | // Ctx::my_judge_type::, Rel>>, Sort, _>(); 2771 | // Below requires weak head reduction to be at least partially implemented (for rels) in order to succeed. 2772 | MyContext::>, Decl, Sort>]>:: 2773 | my_judge_sort::, Set>(); 2774 | MyContext::>, Rel>, Prod>, Rel>>>>, Assum>, Decl, Sort>]>:: 2775 | my_judge_sort::, Rel>>, Set>(); 2776 | MyContext::, Sort>, 2777 | Sort>, 2778 | Assum>]>:: 2779 | my_judge_sort::, Prod>, Rel>>>>, Rel>>, Type>(); 2780 | MyContext::>, Assum>]>:: 2781 | my_whd::, Rel>, Rel>>, Rel>>(); 2782 | // Below requires conversion to be at least partially implemented in order to succeed. 2783 | MyContext::>]>:: 2784 | my_judge_type::, 2785 | App, Rel>, 2786 | Rel>>, 2787 | Rel>, 2788 | Rel>>, 2789 | Prod, App, Rel>, Rel>>>, 2790 | Set>(); 2791 | // Below (probably) requires conversion to be implemented for Flex (assuming betaiotazeta 2792 | // is used during conversion). 2793 | // 2794 | // X : Set, Y := X ⊢ λ x : X . (λ y : (λ Z : Set . Z) Y . y) x : X → (λ Z : Set . Z) Y 2795 | MyContext::, Sort>, Assum>]>:: 2796 | my_judge_type::>, 2797 | App, Rel>, 2798 | Rel>>, 2799 | Rel>, 2800 | Rel>>, 2801 | Prod>, App, Rel>, Rel>>>, 2802 | Set>(); 2803 | MyContext::>]>:: 2804 | my_judge_sort::, Rel>>, Rel>>, _>(); 2805 | MyContext::>]>:: 2806 | my_judge_sort::, Rel>>, Sort>, Type>(); 2807 | // Requires conversion to be implemented for rels. 2808 | MyContext::>]>:: 2809 | my_conv::, Rel>, App, Lambda, Rel>>, Rel>>(); 2810 | // Requires conversion to be implemented for app stacks. 2811 | MyContext::, Sort>>, Assum>]>:: 2812 | my_judge_type::>, 2813 | App>, Rel>>, 2814 | Lambda>>, 2815 | App>>, 2816 | Rel>, 2817 | Rel>, 2818 | App>, 2819 | App>>>, Rel>, 2820 | Rel> 2821 | > 2822 | > 2823 | >>, 2824 | _, 2825 | Set>(); 2826 | // X : Set, Y : (X → X) → Set ⊢ 2827 | // λ f : (∀ x : X → X . Y x) . 2828 | // (λ y : (Y (λ (z : X) . z)) . y) 2829 | // (f (λ z : X . (λ (w : X) . w) z)) 2830 | // Requires conversion to be implemented for lambdas and app stacks. 2831 | MyContext::, Rel>>, Sort>>, Assum>]>:: 2832 | my_judge_type::>, Rel>>>, 2833 | App>, Rel>>, 2834 | App>, 2835 | Lambda>>, 2836 | Rel>>, 2837 | Rel>, 2838 | App, 2839 | Lambda>>, 2840 | App>>>, Rel>, 2841 | Rel>> 2842 | > 2843 | > 2844 | >, 2845 | _, 2846 | Set>(); 2847 | // Requires conversion to be implemented for Set : Type, and flex on lhs. 2848 | // (Note: not sure whether we can actually trigger this conversion with just one universe?) 2849 | MyContext::, Sort>]>:: 2850 | my_conv_sort::, Sort>(); 2851 | // Requires conversion to be implemented for prod, and flex on rhs. 2852 | MyContext::, Sort>, 2853 | Sort>, 2854 | Assum>]>:: 2855 | my_conv::, Sort>, Rel>>, Sort>, 2856 | Rel>(); 2857 | // Requires conversion to be implemented for lambdas on lhs (eta expansion) 2858 | // X : Set, Y : ((X → X) → X → X) → Set ⊢ 2859 | // λ f : (∀ x : (X → X) → X → X . Y x) . 2860 | // (λ y : (Y (λ (z : X → X) . z)) . y) 2861 | // (f (λ z : X → X . (λ (w : X) . z w))) 2862 | MyContext::, Rel>>, 2863 | Prod>, Rel>>>>, 2864 | Sort>>, 2865 | Assum>]>:: 2866 | my_judge_type::>, Rel>>>, 2867 | Prod>>, 2868 | Rel>>>>>, 2869 | App>, Rel>>, 2870 | App>, 2871 | Lambda>>, 2872 | Rel>>>>, 2873 | Rel>>, 2874 | Rel>, 2875 | App, 2876 | Lambda>>, 2877 | Rel>>>>, 2878 | Lambda>>>, 2879 | App>, Rel>>> 2880 | > 2881 | > 2882 | >, 2883 | _, 2884 | Set>(); 2885 | // Requires conversion to be implemented for lambdas on rhs (eta expansion) 2886 | // X : Set, Y : ((X → X) → X → X) → Set ⊢ 2887 | // λ f : (∀ x : (X → X) → X → X . Y x) . 2888 | // (λ y : (Y (λ (z : X → X) . λ (w : X). z w)) . y) 2889 | // (f (λ z : X → X . z)) 2890 | MyContext::, Rel>>, 2891 | Prod>, Rel>>>>, 2892 | Sort>>, 2893 | Assum>]>:: 2894 | my_judge_type::>, Rel>>>, 2895 | Prod>>, 2896 | Rel>>>>>, 2897 | App>, Rel>>, 2898 | App>, 2899 | Lambda>>, 2900 | Rel>>>>, 2901 | Lambda>>>, 2902 | App>, Rel>>>>, 2903 | Rel>, 2904 | App, 2905 | Lambda>>, 2906 | Rel>>>>, 2907 | Rel> 2908 | > 2909 | > 2910 | >, 2911 | _, 2912 | Set>(); 2913 | /* // Correctly fails (not convertible): 2914 | MyContext::, Sort>, 2915 | Sort>, 2916 | Assum>]>:: 2917 | my_conv::, 2918 | Prod, Prod>, Rel>>>>, Rel>>, Sort>>(); */ 2919 | } 2920 | } 2921 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // #![recursion_limit="128"] 2 | // #![feature(generic_associated_types)] 3 | 4 | #[macro_use] 5 | extern crate frunk; 6 | 7 | #[macro_use] 8 | extern crate frunk_core; 9 | 10 | pub mod context; 11 | 12 | fn main() { 13 | println!("Hello, world!"); 14 | } 15 | --------------------------------------------------------------------------------

>::Output, LEnv>; 357 | } 358 | 359 | impl SubsLiftN2 for EsCons { 360 | type Output = EsLift>; 361 | } 362 | 363 | impl SubsLiftN2 for EsShift { 364 | type Output = EsLift>; 365 | } 366 | 367 | pub trait SubsLift { 368 | type Output; 369 | } 370 | 371 | impl SubsLift for A where A : SubsLiftN2 { 372 | type Output = >::Output; 373 | } 374 | 375 | pub trait SubsLiftN { 376 | type Output; 377 | } 378 | 379 | /// lift by 0 380 | impl SubsLiftN for A { 381 | type Output = A; 382 | } 383 | 384 | /// lift by S n 385 | impl SubsLiftN> for A where A : SubsLiftN2 { 386 | type Output = >::Output; 387 | } 388 | 389 | /// shift by N 390 | pub trait SubsShft { 391 | type Output; 392 | } 393 | 394 | impl SubsShft for EsShift where K : IAdd { 395 | type Output = EsShift<>::Output, S1>; 396 | } 397 | 398 | impl SubsShft for EsId { 399 | type Output = EsShift>; 400 | } 401 | 402 | impl SubsShft for EsCons { 403 | type Output = EsShift>; 404 | } 405 | 406 | impl SubsShft for EsLift { 407 | type Output = EsShift>; 408 | } 409 | 410 | /// KDiffN = K - N 411 | pub trait ExpRelLift { 412 | type Output; 413 | } 414 | 415 | /// K - N ≤ 0 → K ≤ N (Lams = Here, i.e. Lams = 0) 416 | impl ExpRelLift for EsLift { 417 | type Output = Inr<(K, Here)>; 418 | } 419 | 420 | /// K - N ≤ 0 → K ≤ N (Lams = There Lams', i.e. Lams = Lams') 421 | impl ExpRelLift, K, Here> for EsLift where Lams : IAdd { 422 | type Output = Inr<(>::Output, Here)>; 423 | } 424 | 425 | /// K - N > 0 → K > N 426 | impl ExpRelLift> for EsLift 427 | where 428 | N : IAdd, 429 | L : ExpRel<>::Output, KDiffN> 430 | { 431 | type Output = >::Output, KDiffN>>::Output; 432 | } 433 | 434 | /// KDiffN = K - N 435 | pub trait ExpRelId { 436 | type Output; 437 | } 438 | 439 | /// K - N ≤ 0 → K ≤ N (Lams = Here, i.e. Lams = 0) 440 | impl ExpRelId for EsId { 441 | type Output = Inr<(K, Here)>; 442 | } 443 | 444 | /// K - N ≤ 0 → K ≤ N (Lams = There Lams', i.e. Lams = Lams') 445 | impl ExpRelId, K, Here> for EsId where Lams : IAdd { 446 | type Output = Inr<(>::Output, Here)>; 447 | } 448 | 449 | /// K - N > 0 → K > N (Lams = Here, i.e. Lams = 0) 450 | impl ExpRelId> for EsId { 451 | type Output = Inr<(K, There)>; 452 | } 453 | 454 | /// K - N > 0 → K > N (Lams = There Lams', i.e. Lams = Lams') 455 | impl ExpRelId, K, There> for EsId where Lams : IAdd { 456 | type Output = Inr<(>::Output, There)>; 457 | } 458 | 459 | /// Expands de Bruijn k in the explicit substitution subs 460 | /// lams accumulates de shifts to perform when retrieving the i-th value 461 | /// the rules used are the following: 462 | /// 463 | /// [id]k --> k 464 | /// [S.t]1 --> t 465 | /// [S.t]k --> [S](k-1) if k > 1 466 | /// [^n o S] k --> [^n]([S]k) 467 | /// [(%n S)] k --> k if k <= n 468 | /// [(%n S)] k --> [^n]([S](k-n)) 469 | /// 470 | /// The result is either (Inl(lams,v)) when the variable is 471 | /// substituted by value [v] under lams binders (i.e. v *has* to be 472 | /// shifted by lams), or (Inr (k',p)) when the variable k is just relocated 473 | /// as k'; p is Here if the variable points inside subs and There(k) if the 474 | /// variable points k bindings beyond subs (cf argument of ESID). 475 | pub trait ExpRel { 476 | type Output; 477 | } 478 | /*let rec exp_rel lams k subs = 479 | match subs with 480 | | CONS (def,_) when k <= Array.length def 481 | -> Inl(lams,def.(Array.length def - k)) 482 | | CONS (v,l) -> exp_rel lams (k - Array.length v) l 483 | | LIFT (n,_) when k<=n -> Inr(lams+k,None) 484 | | LIFT (n,l) -> exp_rel (n+lams) (k-n) l 485 | | SHIFT (n,s) -> exp_rel (n+lams) k s 486 | | ESID n when k<=n -> Inr(lams+k,None) 487 | | ESID n -> Inr(lams+k,Some (k-n))*/ 488 | 489 | /// k ≤ 1 490 | impl ExpRel for EsCons 491 | { 492 | type Output = Inl<(Lams, Def)>; 493 | } 494 | 495 | /// k > 1 496 | impl ExpRel> for EsCons where L : ExpRel { 497 | type Output = >::Output; 498 | } 499 | 500 | impl ExpRel for EsLift 501 | where 502 | There : ISub>, 503 | Self : ExpRelLift as ISub>>::Output>, 504 | { 505 | type Output = as ISub>>::Output>>::Output; 506 | } 507 | 508 | impl ExpRel for EsShift 509 | where 510 | N : IAdd, 511 | S : ExpRel<>::Output, K>, 512 | { 513 | type Output = >::Output, K>>::Output; 514 | } 515 | 516 | impl ExpRel for EsId 517 | where 518 | There : ISub, 519 | Self : ExpRelId as ISub>::Output>, 520 | { 521 | type Output = as ISub>::Output>>::Output; 522 | } 523 | 524 | pub trait ExpandRel { 525 | type Output; 526 | } 527 | 528 | impl ExpandRel for Subs where Subs : ExpRel { 529 | type Output = >::Output; 530 | } 531 | 532 | //Selector> for HCons 533 | 534 | /* #[derive(Generic, LabelledGeneric)] 535 | pub struct Context { 536 | subs: Subs, 537 | } */ 538 | 539 | pub trait RawContext { 540 | type Subs; 541 | } 542 | 543 | impl RawContext for T { 544 | type Subs = Self; 545 | } 546 | 547 | pub trait Context : RawContext { 548 | }/*+ Sized where Self::Subs : Generic /* where Self : Generic*/ { 549 | }*/ 550 | 551 | impl Context for T /*where T : Generic */{ 552 | } 553 | 554 | /* Context: IAdd where >::Output 555 | 556 | impl IAdd for C */ 557 | 558 | /* impl LiftFrom */ 559 | 560 | /* pub trait ContextSubs { 561 | type Output : Context + LiftFrom<>; 562 | } */ 563 | 564 | /* impl LiftFrom> for >::Output where 565 | Prefix: HList + Add, 566 | Suffix: Default, */ 567 | 568 | /// RDecl is (canonically) either Def or Assum 569 | pub trait RDecl// 570 | //where Ctx::Subs : AtIndex, 571 | { 572 | type Type;// : JudgeOfSort<>; 573 | } 574 | 575 | // #[derive(Generic, LabelledGeneric)] 576 | pub struct Assum { 577 | ty: Type, 578 | } 579 | 580 | // #[derive(Generic, LabelledGeneric)] 581 | pub struct Decl { 582 | bd: Body, 583 | ty: Type, 584 | } 585 | 586 | impl RDecl for Assum { 587 | type Type = Type; 588 | } 589 | 590 | impl RDecl for Decl { 591 | type Type = Type; 592 | } 593 | 594 | // #[derive(Generic)] 595 | pub struct Set; 596 | 597 | // #[derive(Generic)] 598 | pub struct Type; 599 | 600 | pub struct App { 601 | fun: Fun, 602 | // args: Args, 603 | arg: Arg, 604 | } 605 | 606 | pub struct Lambda { 607 | ty: Type, 608 | bd: Body, 609 | } 610 | 611 | pub struct Prod { 612 | domain: Domain, 613 | codomain: CoDomain, 614 | } 615 | 616 | // #[derive(Generic, LabelledGeneric)] 617 | pub struct Sort { 618 | sort: S, 619 | } 620 | 621 | // #[derive(Generic, LabelledGeneric)] 622 | pub struct Rel { 623 | index: Index, 624 | } 625 | 626 | /// The generic lifting function 627 | pub trait ExLiftN { 628 | type Output; 629 | } 630 | 631 | impl ExLiftN for Prod 632 | where 633 | T: ExLiftN, 634 | El : ELift, 635 | C: ExLiftN<::Output>, 636 | { 637 | type Output = Prod<>::Output, ::Output>>::Output>; 638 | } 639 | 640 | impl ExLiftN for Lambda 641 | where 642 | T: ExLiftN, 643 | El : ELift, 644 | B: ExLiftN<::Output>, 645 | { 646 | type Output = Lambda<>::Output, ::Output>>::Output>; 647 | } 648 | 649 | impl ExLiftN for App 650 | where 651 | F: ExLiftN, 652 | A: ExLiftN, 653 | { 654 | type Output = App<>::Output, >::Output>; 655 | } 656 | 657 | impl ExLiftN for Sort { 658 | type Output = Self; 659 | } 660 | 661 | /// Lifting 662 | 663 | impl ExLiftN for Rel 664 | where 665 | El : RelocRel, 666 | { 667 | type Output = Rel<>::Output>; 668 | } 669 | 670 | /// Lifting the binding depth across k bindings 671 | pub trait LiftN { 672 | type Output; 673 | } 674 | 675 | impl LiftN for T 676 | where 677 | ElId : EShift>, 678 | // NOTE: ELiftN expects N+1, so it lifts by N-1, which is what we want here. 679 | >>::Output : ELiftN, 680 | T : ExLiftN<<>>::Output as ELiftN>::Output>, 681 | { 682 | type Output = >>::Output as ELiftN>::Output>>::Output; 683 | } 684 | 685 | pub trait Lift : LiftN 686 | { 687 | type Output; 688 | } 689 | 690 | impl Lift for T where T : LiftN 691 | { 692 | type Output = >::Output; 693 | } 694 | 695 | /// Lamv = Subs, N = Shifts. Subs are evaluated first. 696 | /// 697 | /// Reminder : N = Here means None, and N = Theirs gives the actual N' we want. 698 | pub trait SubstRec { 699 | type Output; 700 | } 701 | 702 | impl SubstRec for Prod 703 | where 704 | T: SubstRec, 705 | C: SubstRec, LamV, LV>, 706 | { 707 | type Output = Prod<>::Output, , LamV, LV>>::Output>; 708 | } 709 | 710 | impl SubstRec for Lambda 711 | where 712 | T: SubstRec, 713 | B: SubstRec, LamV, LV>, 714 | { 715 | type Output = Lambda<>::Output, , LamV, LV>>::Output>; 716 | } 717 | 718 | impl SubstRec for App 719 | where 720 | F: SubstRec, 721 | A: SubstRec, 722 | { 723 | type Output = App<>::Output, >::Output>; 724 | } 725 | 726 | impl SubstRec for Sort { 727 | type Output = Self; 728 | } 729 | 730 | /// Substitutions 731 | 732 | /// Trait used for dealing with inbounds substitutions. 733 | /// 734 | /// NOTE: We secretly know that LV = LamV::PeanoLen, and therefore 735 | /// LV = Theirs at all times. 736 | /// 737 | /// NOTE: IndexDiffK = K - Depth (for real; it is positive). 738 | /// 739 | /// NOTE: LVDiff = (IndexDiffK + 1) - LV (+ 1, so Here represents 0) 740 | /// 741 | /// LDiff = Here → (K - Depth + Here) - (LV' + Here) ≤ Here, i.e. K - Depth ≤ LV'. 742 | /// 743 | /// As a result, in the Here case we can assume K - Depth is in bounds and therefore 744 | /// AtIndex should always succeed for IndexDiffK. 745 | /// 746 | /// (We may not actually need to know LV positive for this to work, but it's convincing). 747 | /*/// NOTE: We secretly know that LV = LamV::PeanoLen, and therefore 748 | /// LV = Theirs at all times. This allows us to know 749 | /// that if LDiff = Here (i.e. (K - Depth) - LV ≤ 0, i.e. 750 | /// K - Depth ≤ LV), then K - Depth is 751 | /// then */ 752 | pub trait SubstRel2 { 753 | type Output; 754 | } 755 | 756 | /// Here case : InDiffK is in-bounds and N = Here. 757 | /// 758 | /// Important reminder: if N = Here, don't lift! 759 | impl SubstRel2 for Rel 760 | where 761 | LamV : AtIndex, 762 | { 763 | type Output =>::Output; 764 | } 765 | 766 | /// Here case : InDiffK is in-bounds and N = There N'. 767 | /// 768 | /// Important reminder: if N = Here, don't lift! 769 | impl SubstRel2, LamV, LV, IndexDiffK, Here> for Rel 770 | where 771 | LamV : AtIndex, 772 | >::Output : Lift, 773 | { 774 | type Output = <>::Output as Lift>::Output; 775 | } 776 | 777 | /// There case : LDiff = There. 778 | /// Then Here < (K - Depth + Here) - (LV' + Here), i.e. 779 | /// Here < (K - Depth) - LV', which implies Here < K - LV'. Fortunately this implies that 780 | /// K > Here + LV' = LV; so we can replicate the effect of stripping off the There<_> from the 781 | /// output of K - LV' (to get the real answer) by instead stripping it off of K up front. The 782 | /// subtraction is still in bounds, it just becomes Here ≤ K' - LV'; and again, we should be 783 | /// exhaustive here for all indices (there should be no missed cases). 784 | impl SubstRel2> for Rel*/> 785 | where 786 | Index : ISub, 787 | { 788 | type Output = Rel<>::Output>; 789 | } 790 | 791 | /// LV' < K - Depth, i.e. There ≤ K - Depth, so 792 | /// Depth ≤ K - There. 793 | /// 794 | /// Trait used for dealing with substitutions. 795 | /// 796 | /// NOTE: Lift (K = There, IndexDiffK = Self - K') 797 | pub trait SubstRel { 798 | type Output; 799 | } 800 | 801 | /// NOTE: Treat N as 1 + K', where K' is what we actually care about. 802 | /// 803 | /// NOTE: Here = ((1 + Index) - N) 804 | /// 805 | /// NOTE: If Here, Index ≤ K', so we return Index unchanged. 806 | impl SubstRel for Rel { 807 | type Output = Rel; 808 | } 809 | 810 | /// NOTE: Treat N as 1 + K', where K' is what we actually care about. 811 | /// 812 | /// NOTE: There = ((1 + Index) - N) 813 | /// 814 | /// NOTE: If There, K' < Index, so we split further. 815 | impl SubstRel> for Rel 816 | where 817 | // Recall : PeanoLen is actually len + 1, so this all works out 818 | // (output is 1+ as well). This is lv - (k - depth), i.e. (k - depth) ≤ lv. 819 | There : ISub, 820 | // Note that if lv < k - depth, depth < k - lv, so k - lv > 0; therefore, 821 | // since subtraction normally returns output + 1, and we know the output is 822 | // positive, we can get the real output by subtracting 1 from k first (it 823 | // won't mess up at 0 because (k - 1) - lv ≥ 0). 824 | // Even though it's not always necessary, we also compute k - lv here to 825 | // be able to extract the There pattern (if k - depth ≤ lv) 826 | Rel : SubstRel2 as ISub>::Output>, 827 | /* else if k-depth <= lv then lift_substituend depth lamv.(k-depth-1) 828 | 829 | */ 830 | // Self : IAdd, 831 | { 832 | type Output = as ISub>::Output>>::Output; 833 | } 834 | 835 | impl SubstRec for Rel 836 | where 837 | // NOTE: N is "really" There, where N' is what we care about. 838 | There : ISub, 839 | // Compute the necessary relocation. 840 | Self: SubstRel as ISub>::Output>, 841 | { 842 | type Output = as ISub>::Output>>::Output; 843 | } 844 | /* 845 | fn substrec(&self, 846 | &(depth, ref lamv): &(Option, &[Substituend])) -> IdxResult 847 | where 848 | T: Borrow, 849 | { 850 | match *self { 851 | Constr::Rel(k_) => { 852 | // FIXME: For below, ensure u32 to usize is always a valid cast. 853 | let d = depth.map(u32::from).unwrap_or(0) as usize; 854 | // NOTE: This can only fail if we compile with addresses under 64 bits. 855 | let k = usize::try_from(k_)?; 856 | // After the above, we know k is a valid non-negative i64. 857 | if k <= d { 858 | Ok(self.clone()) 859 | } else if let Some(sub) = lamv.get(k - d - 1) { 860 | // Note that k - d above is valid (and > 0) because 0 ≤ d < k; 861 | // therefore, 0 ≤ k - depth - 1, so that is valid. 862 | // Also, the unwrap() below is granted because 0 < k. 863 | // FIXME: There is a better way of dealing with this. 864 | sub.borrow().lift(depth.unwrap()) 865 | } else { 866 | // k - lamv.len() is valid (and > 0) because if lamv.get(k - d - 1) = None, 867 | // lamv.len() ≤ k - d - 1 < k - d ≤ k (i.e. lamv.len() < k), so 868 | // 0 < k - lamv.len() (k - lamv.len() is positive). 869 | // Additionally, since we know 0 < lamv.len() < k, and k is a valid positive 870 | // i64, lamv.len() is also a valid positive i64. 871 | // So the cast is valid. 872 | Ok(Constr::Rel(k_ - lamv.len() as i64)) 873 | } 874 | }, 875 | _ => self.map_constr_with_binders( 876 | |&mut (ref mut depth, _)| { 877 | *depth = match *depth { 878 | None => Some(Idx::ONE), 879 | Some(depth) => Some(depth.checked_add(Idx::ONE)?), 880 | }; 881 | Ok(()) 882 | }, 883 | Self::substrec, 884 | &(depth, lamv) 885 | ) 886 | } 887 | } 888 | */ 889 | 890 | /* 891 | /// (subst1 M c) substitutes M for Rel(1) in c 892 | /// we generalise it to (substl [M1,...,Mn] c) which substitutes in parallel 893 | /// M1,...,Mn for respectively Rel(1),...,Rel(n) in c 894 | pub fn substn_many(&self, lamv: &[Substituend], n: Option) -> IdxResult 895 | where 896 | T: Borrow, 897 | { 898 | let lv = lamv.len(); 899 | if lv == 0 { return Ok(self.clone()) } 900 | else { self.substrec(&(n, lamv)) } 901 | } 902 | */ 903 | /// Reminder : N = Here means None, and N = Theirs gives the actual N' we want. 904 | pub trait SubstNMany { 905 | type Output; 906 | } 907 | 908 | impl SubstNMany for C 909 | { 910 | type Output = C; 911 | } 912 | 913 | /// FIXME: Pass around PeanoLen-1 (which is actually the proper length). 914 | impl SubstNMany, N> for C 915 | where 916 | LamV : PeanoLen, 917 | C : SubstRec, as PeanoLen>::PeanoLen>, 918 | { 919 | type Output = , as PeanoLen>::PeanoLen>>::Output; 920 | } 921 | 922 | /* 923 | pub fn substnl(&self, laml: C, n: Option) -> IdxResult 924 | where 925 | C: IntoIterator, 926 | T: Borrow, 927 | { 928 | let lamv: Vec<_> = laml.into_iter().map( |i| Substituend::make(i) ).collect(); 929 | self.substn_many(&lamv, n) 930 | } 931 | 932 | pub fn substl(&self, laml: C) -> IdxResult 933 | where 934 | C: IntoIterator, 935 | T: Borrow, 936 | { 937 | self.substnl(laml, None) 938 | } 939 | */ 940 | 941 | pub trait Subst1 { 942 | type Output; 943 | } 944 | 945 | /// Reminder : N = Here means None, and N = Theirs gives the actual N' we want. 946 | impl Subst1 for C 947 | where 948 | C : SubstNMany, 949 | { 950 | type Output = >::Output; 951 | } 952 | /* 953 | pub fn subst1(&self, lam: &Constr) -> IdxResult { 954 | let lamv = [Substituend::make(lam)]; 955 | self.substn_many(&lamv, None) 956 | } 957 | */ 958 | 959 | pub trait Reds { 960 | type Delta; 961 | } 962 | 963 | pub struct BetaDeltaIota; 964 | 965 | pub struct BetaIotaZeta; 966 | 967 | impl Reds for BetaDeltaIota { 968 | type Delta = True; 969 | } 970 | 971 | impl Reds for BetaIotaZeta { 972 | type Delta = False; 973 | } 974 | 975 | pub trait Infos { 976 | type Flags : Reds; 977 | type Rels; 978 | } 979 | 980 | pub trait RefValueCacheRel { 981 | type Output; 982 | } 983 | 984 | /// Rel out of bounds (NOTE: should this actually be an error?) 985 | impl RefValueCacheRel for TNone { 986 | type Output = TNone; 987 | } 988 | 989 | /// Rel in bounds, but an Assum, not a Decl (hence no body). 990 | impl RefValueCacheRel for TSome> { 991 | type Output = TNone; 992 | } 993 | 994 | /// Rel in bounds, and a Decl (hence has body) 995 | impl RefValueCacheRel for TSome> 996 | where 997 | Body : Lift, 998 | >::Output : Inject, 999 | { 1000 | type Output = TSome<<>::Output as Inject>::Output>; 1001 | } 1002 | 1003 | pub trait RefValueCache { 1004 | type Output; 1005 | } 1006 | 1007 | impl RefValueCache> for Info 1008 | where 1009 | Info::Rels : AtIndexOpt, 1010 | >::Output : RefValueCacheRel, 1011 | { 1012 | type Output = <>::Output as RefValueCacheRel>::Output; 1013 | } 1014 | 1015 | /// FVal(c) represents the constr c. 1016 | /// c must be in normal form and neutral (i.e. not a lambda, a construct or a 1017 | /// (co)fix, because they may produce redexes by applying them, 1018 | /// or putting them in a case) 1019 | pub struct FVal { 1020 | c: C, 1021 | } 1022 | 1023 | /// FFlex(c) represents the RelKey / ConstKey c. 1024 | /// 1025 | /// NOTE: Might be able to replace FFlex(c) with FCbn(c, EsId(Here)), since evaluating in that 1026 | /// (empty) environment is essentially what we do when grabbing the contents of the flex. 1027 | pub struct FFlex { 1028 | c: C, 1029 | } 1030 | 1031 | /// FStk(v,stk) represents an irreductible value [v] in the stack [stk]. 1032 | /// (Note that [v] is a WhdValue and [Stk] is a *reversed* Stack; the 1033 | /// reversal is necessary to emulate the behavior of Zip). 1034 | pub struct FStk { 1035 | v: V, 1036 | stk: Stk, 1037 | } 1038 | 1039 | /// FCbn(t,S) is the term [S]t. It is used to delay evaluation. 1040 | /// (Note that [t] is a Constr and [S] is a substitution). 1041 | pub struct FCbn { 1042 | t: T, 1043 | s: S, 1044 | } 1045 | 1046 | /// ZApp is a delayed application of the head to A on a Stack. 1047 | pub struct ZApp { 1048 | a: A, 1049 | } 1050 | 1051 | /// ZShift is a delayed shift of the head by K on a Stack. 1052 | /// 1053 | /// NOTE: Currently K is the real shift, but we could turn it into K = Pred with K' the real 1054 | /// shift if needed (this would allow shifts by 0). 1055 | pub struct ZShift { 1056 | k: K, 1057 | } 1058 | 1059 | /// WhdAppendStack appends V to stack Self 1060 | pub trait WhdAppendStack { 1061 | type Output; 1062 | } 1063 | 1064 | impl WhdAppendStack for S { 1065 | type Output = HCons, S>; 1066 | } 1067 | 1068 | /// StkShift adds a delayed shift by N to stack Self 1069 | /// (collapses shifts in the stack). 1070 | pub trait StkShift { 1071 | type Output; 1072 | } 1073 | 1074 | impl StkShift for HCons, S> where N : IAdd { 1075 | type Output = HCons>::Output>, S>; 1076 | } 1077 | 1078 | impl StkShift for HCons, S> { 1079 | type Output = HCons, Self>; 1080 | } 1081 | 1082 | impl StkShift for HNil { 1083 | type Output = HCons, Self>; 1084 | } 1085 | 1086 | /// Lifting by K. Preserves sharing where theoretically useful (norm = Red). 1087 | pub trait WhdLft { 1088 | type Output; 1089 | } 1090 | 1091 | /* /// Lifting a stack by K: add the lift to the stack. NOTE: need to reverse this! 1092 | impl WhdLft for FStk where S : StkShift { 1093 | type Output = >::Output; 1094 | } 1095 | 1096 | /// Lifting a value by K: just lift the value directly using exlittn (it's normal 1097 | /// so this is fine). 1098 | impl WhdLft for FStk where S : StkShift { 1099 | type Output = >::Output; 1100 | } */ 1101 | 1102 | impl WhdLft for V { 1103 | type Output = FStk]>; 1104 | } 1105 | 1106 | /// WhdLift lifts Self by K' if K = There K', otherwise does not lift. 1107 | pub trait WhdLift { 1108 | type Output; 1109 | } 1110 | 1111 | impl WhdLift for F { 1112 | type Output = F; 1113 | } 1114 | 1115 | impl WhdLift> for F where F : WhdLft { 1116 | type Output = >::Output; 1117 | } 1118 | 1119 | /// Turn a rel I into a closed value, where Self is the result 1120 | /// of running ExpandRel for environment E. 1121 | pub trait ClosRel { 1122 | type Output; 1123 | } 1124 | 1125 | impl ClosRel for Inl<(N, MT)> where MT : WhdLift { 1126 | type Output = >::Output; 1127 | } 1128 | 1129 | /// Note: currently ExpandRel returns the real K for Inr cases, rather than 1130 | /// There K; but we could also change ExpandRel to be a bit simpler and have 1131 | /// Inr only accept There K. 1132 | impl ClosRel for Inr<(K, Here)> { 1133 | type Output = FVal>; 1134 | } 1135 | 1136 | /// See above comment 1137 | /// 1138 | /// NOTE: k-p guaranteed non-negative. 1139 | impl ClosRel for Inr<(K, There