wip
This commit is contained in:
parent
5b5601f5ee
commit
6fc0be28e1
1 changed files with 135 additions and 4 deletions
139
main.ts
139
main.ts
|
@ -5,7 +5,11 @@ export type expr =
|
||||||
| { kind: "universe"; level: number }
|
| { kind: "universe"; level: number }
|
||||||
| { kind: "pi"; abs: abstraction }
|
| { kind: "pi"; abs: abstraction }
|
||||||
| { kind: "lambda"; abs: abstraction }
|
| { kind: "lambda"; abs: abstraction }
|
||||||
| { kind: "app"; left: expr; right: expr };
|
| { kind: "app"; left: expr; right: expr }
|
||||||
|
|
||||||
|
// Types
|
||||||
|
| { kind: "cons"; name: variable; type: expr }
|
||||||
|
| { kind: "elim"; name: variable; eval: (_: expr) => expr };
|
||||||
|
|
||||||
export interface abstraction {
|
export interface abstraction {
|
||||||
x: variable;
|
x: variable;
|
||||||
|
@ -20,6 +24,7 @@ export type variable =
|
||||||
| { kind: "string"; name: string }
|
| { kind: "string"; name: string }
|
||||||
| { kind: "gensym"; name: string; n: number }
|
| { kind: "gensym"; name: string; n: number }
|
||||||
| { kind: "dummy" };
|
| { kind: "dummy" };
|
||||||
|
const dummy: variable = { kind: "dummy" };
|
||||||
|
|
||||||
export interface Substitution {
|
export interface Substitution {
|
||||||
x: variable;
|
x: variable;
|
||||||
|
@ -52,6 +57,9 @@ export function subst(s: Substitution[], e: expr): expr {
|
||||||
return { kind: "lambda", abs: substAbstraction(s, e.abs) };
|
return { kind: "lambda", abs: substAbstraction(s, e.abs) };
|
||||||
case "app":
|
case "app":
|
||||||
return { kind: "app", left: subst(s, e.left), right: subst(s, e.right) };
|
return { kind: "app", left: subst(s, e.left), right: subst(s, e.right) };
|
||||||
|
case "cons":
|
||||||
|
case "elim":
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +287,7 @@ export function ppExpr(e: expr): string {
|
||||||
case "pi":
|
case "pi":
|
||||||
if (occursIn(e.abs.x, e.abs.body)) {
|
if (occursIn(e.abs.x, e.abs.body)) {
|
||||||
return `(∏ (${ppVariable(e.abs.x)} : ${ppExpr(e.abs.type)}), ${ppExpr(
|
return `(∏ (${ppVariable(e.abs.x)} : ${ppExpr(e.abs.type)}), ${ppExpr(
|
||||||
e.abs.type,
|
e.abs.body,
|
||||||
)})`;
|
)})`;
|
||||||
}
|
}
|
||||||
return `(${ppExpr(e.abs.type)} → ${ppExpr(e.abs.body)})`;
|
return `(${ppExpr(e.abs.type)} → ${ppExpr(e.abs.body)})`;
|
||||||
|
@ -301,13 +309,126 @@ export function ppContext(ctx: context): string {
|
||||||
return `[${ss.join(", ")}]`;
|
return `[${ss.join(", ")}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Types
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// W-types
|
||||||
|
|
||||||
|
interface InductiveTypeDefinition {
|
||||||
|
name: string;
|
||||||
|
labels: InductiveTypeLabel[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InductiveTypeLabel {
|
||||||
|
name: string;
|
||||||
|
type: expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InductiveType {
|
||||||
|
// The new context
|
||||||
|
ctx: context;
|
||||||
|
|
||||||
|
// Name of the type
|
||||||
|
T: variable;
|
||||||
|
|
||||||
|
// Recursor
|
||||||
|
rec: variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defineInductiveType(
|
||||||
|
ctx: context,
|
||||||
|
def: InductiveTypeDefinition,
|
||||||
|
): InductiveType {
|
||||||
|
const ctx2 = [...ctx];
|
||||||
|
const Tvar: variable = { kind: "string", name: def.name };
|
||||||
|
ctx2.push({
|
||||||
|
x: Tvar,
|
||||||
|
type: { kind: "universe", level: 0 },
|
||||||
|
});
|
||||||
|
const T: expr = { kind: "var", x: Tvar };
|
||||||
|
|
||||||
|
// First, we need A, which represents the labels of this W-type
|
||||||
|
// The size of A is equal to the number of constructors we have
|
||||||
|
const Aname = refresh({ kind: "string", name: `A` });
|
||||||
|
const A: expr = { kind: "var", x: Aname };
|
||||||
|
ctx2.push({ x: Aname, type: { kind: "universe", level: 0 } });
|
||||||
|
const labels: variable[] = def.labels.map((label, idx) => {
|
||||||
|
const newName = refresh({
|
||||||
|
kind: "string",
|
||||||
|
name: `cons${idx}`,
|
||||||
|
});
|
||||||
|
ctx2.push({ x: newName, type: A });
|
||||||
|
return newName;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now we need B : A -> U, which is the arity of labels
|
||||||
|
const Bname = refresh({ kind: "string", name: `B` });
|
||||||
|
const B: expr = { kind: "var", x: Bname };
|
||||||
|
|
||||||
|
function inferArity(ctx: context, e: expr): number {
|
||||||
|
switch (e.kind) {
|
||||||
|
case "var": {
|
||||||
|
const value = lookupValue(e.x, ctx);
|
||||||
|
if (!value) return 0;
|
||||||
|
return inferArity(ctx, value);
|
||||||
|
}
|
||||||
|
case "pi":
|
||||||
|
return 1 + inferArity(ctx, e.abs.body);
|
||||||
|
case "app":
|
||||||
|
case "lambda":
|
||||||
|
case "universe":
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// biome-ignore lint/complexity/noForEach: <explanation>
|
||||||
|
const labelArities: number[] = def.labels.forEach((label, idx) => {
|
||||||
|
const arity = inferArity(ctx2, label.type);
|
||||||
|
console.log(`arity(${ppExpr(label.type)}) = ${arity}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the supremum function
|
||||||
|
const supName: variable = refresh({ kind: "string", name: `sup` });
|
||||||
|
const sup_a_name: variable = refresh({ kind: "string", name: "a" });
|
||||||
|
const sup_a: expr = { kind: "var", x: sup_a_name };
|
||||||
|
const supType: expr = {
|
||||||
|
kind: "pi",
|
||||||
|
abs: {
|
||||||
|
x: dummy,
|
||||||
|
type: {
|
||||||
|
kind: "pi",
|
||||||
|
abs: {
|
||||||
|
x: sup_a_name,
|
||||||
|
type: A,
|
||||||
|
body: {
|
||||||
|
kind: "pi",
|
||||||
|
abs: {
|
||||||
|
x: dummy,
|
||||||
|
type: { kind: "app", left: B, right: sup_a },
|
||||||
|
body: T,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: T,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ctx2.push({
|
||||||
|
x: supName,
|
||||||
|
type: supType,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now we have the W-type representing this
|
||||||
|
|
||||||
|
return ctx2;
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Testing
|
// Testing
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
const ctx: context = [];
|
const ctx: context = [];
|
||||||
|
|
||||||
const dummy: variable = { kind: "dummy" };
|
|
||||||
const varify = (name: string): expr => ({
|
const varify = (name: string): expr => ({
|
||||||
kind: "var",
|
kind: "var",
|
||||||
x: { kind: "string", name },
|
x: { kind: "string", name },
|
||||||
|
@ -383,9 +504,19 @@ function test() {
|
||||||
};
|
};
|
||||||
define("result", normalize(ctx, evaled));
|
define("result", normalize(ctx, evaled));
|
||||||
|
|
||||||
|
const N2 = varify("N2");
|
||||||
|
const N2toN2: expr = { kind: "pi", abs: { x: dummy, type: N2, body: N2 } };
|
||||||
|
const ctx2 = defineInductiveType(ctx, {
|
||||||
|
name: "N2",
|
||||||
|
labels: [
|
||||||
|
{ name: "zero", type: N2 },
|
||||||
|
{ name: "suc", type: N2toN2 },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
console.log("ctx =");
|
console.log("ctx =");
|
||||||
// biome-ignore lint/complexity/noForEach: <explanation>
|
// biome-ignore lint/complexity/noForEach: <explanation>
|
||||||
ctx.forEach(({ x, type, value }, idx) => {
|
ctx2.forEach(({ x, type, value }, idx) => {
|
||||||
console.log(
|
console.log(
|
||||||
` ${idx === 0 ? "[" : ","} ${ppVariable(x)} : ${ppExpr(type)}${
|
` ${idx === 0 ? "[" : ","} ${ppVariable(x)} : ${ppExpr(type)}${
|
||||||
value ? ` = ${ppExpr(value)}` : ""
|
value ? ` = ${ppExpr(value)}` : ""
|
||||||
|
|
Loading…
Reference in a new issue