75TM37DMPXA7YQPWZ4672OA3CUJNHYVIE5UFM2H6FHZMPGVMQS2AC
axi[$x = y in NN [x in NN, y in NN]$],
uni(right_label: "(3, 6)")[$"suc"(x) = "suc"(y) in NN [x in NN, y in NN]$],
axi[$x in NN$],
axi[$y in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x)$],
bin(right_label: "(5)")[$"natrec"(x, 0, (u, v) "suc"(v)) = x in NN$],
uni(right_label: "(3)")[$"suc"("natrec"(x, 0, (u, v) "suc"(v))) = "suc"(x) in NN$],
uni(right_label: "natrec")[$"natrec"("suc"(x), 0, (u, v) "suc"(v))) = "suc"(x) in NN$],
#tree(
axi[$"eq"_"xy-suc" in "Eq"(NN, "suc"(x), "suc"(y)) ["eq"_"xy" in "Eq"(NN, x, y), x in NN, y in NN]$],
uni[$lambda(("eq"_"xy") "eq"_"xy-suc") in "Eq"(NN, x, y) arrow.r "Eq"(NN, "suc"(x), "suc"(y))$],
)
// #tree(
// axi[$"eq"_"xy-suc" in "Eq"(NN, "suc"(x), "suc"(y)) ["eq"_"xy" in "Eq"(NN, x, y), x in NN, y in NN]$],
// uni[$lambda(("eq"_"xy") "eq"_"xy-suc") in "Eq"(NN, x, y) arrow.r "Eq"(NN, "suc"(x), "suc"(y))$],
// )
#tree(
axi[$"eq" in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x) [x in NN]$],
uni[$"natrec"(x, 0, (u, v) "suc"(v)) = x in NN [x in NN]$],
uni(right_label: "macro")[$plus.circle(x, 0) = x in NN [x in NN]$],
)
// #tree(
// axi[$"eq" in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x) [x in NN]$],
// uni[$"natrec"(x, 0, (u, v) "suc"(v)) = x in NN [x in NN]$],
// uni(right_label: "macro")[$plus.circle(x, 0) = x in NN [x in NN]$],
// )
tree(
// axi[$c in "Eq"(NN, split1, 0), x)$],
axi[$split1 equiv x in NN [x in NN]$],
uni(right_label: "macro")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
)
// tree(
// // axi[$c in "Eq"(NN, split1, 0), x)$],
// axi[$split1 equiv x in NN [x in NN]$],
// uni(right_label: "macro")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
// )
tree(
axi[$plus.circle(x, 0) equiv split1 [x in NN]$],
axi[$split1 equiv x [x in NN]$],
bin(right_label: "trans")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
)
}
// tree(
// axi[$plus.circle(x, 0) equiv split1 [x in NN]$],
// axi[$split1 equiv x [x in NN]$],
// bin(right_label: "trans")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
// )
// }
module extraexercises where
open import Data.Nat
open import Relation.Binary.PropositionalEquality as Eq
open Eq.≡-Reasoning
/**
* Terms e ::= x | () | λx. e | e e | (e : A)
* Types A, B, C ::= 1 | α | ^α | ∀α. A | A → B
* Monotypes τ, σ ::= 1 | α | ^α | τ → σ
* Contexts Γ, ∆, Θ ::= · | Γ, α | Γ, x : A
* | Γ, ^α | Γ, ^α = τ | Γ, I^α
* Complete Contexts Ω ::= · | Ω, α | Ω, x : A
* | Ω, ^α = τ | Ω, I^
*/
export type Term =
| { kind: "var"; name: string }
| { kind: "unit" }
| { kind: "lambda"; name: string; body: Term }
| { kind: "app"; func: Term; arg: Term }
| { kind: "annot"; term: Term; type: Type };
export type Type =
| { kind: "unit" }
| { kind: "var"; name: string }
| { kind: "existential"; name: string }
| { kind: "poly"; name: string; type: Type }
| { kind: "arrow"; input: Type; output: Type };
export type Monotype =
| { kind: "unit" }
| { kind: "var"; name: string }
| { kind: "existential"; name: string }
| { kind: "arrow"; input: Monotype; output: Monotype };
export type ContextEntry =
| { kind: "typeVar"; name: string }
| { kind: "termAnnot"; name: string; type: Type }
| { kind: "existentialVar"; name: string }
| { kind: "existentialSolved"; name: string; type: Monotype }
| { kind: "marker"; name: string };
export type CompleteContextEntry =
| { kind: "typeVar"; name: string }
| { kind: "termAnnot"; name: string; type: Type }
| { kind: "existentialSolved"; name: string; type: Monotype }
| { kind: "marker"; name: string };
// Helper functions for dealing with contexts
import { ContextEntry, Type } from "./data";
import { isEqual } from "lodash";
/** Γ |- A (is the given type in this context?) */
export function isTypeInContext(type: Type, ctx: ContextEntry[]): boolean {
for (const entry of ctx) {
switch (entry.kind) {
case "termAnnot":
if (isEqual(entry.type, type)) return true;
break;
default:
continue;
}
}
return false;
}
import { isTypeInContext } from "./contexts";
import { ContextEntry, Term, Type } from "./data";
function check(
ctx: ContextEntry[],
term: Term,
type: Type
): [boolean, ContextEntry[]] {
switch (term.kind) {
case "var":
break;
case "unit":
return [type.kind === "unit", ctx];
case "lambda": {
// Get A and B first
if (type.kind !== "arrow") return [false, ctx];
const { input: A, output: B } = type;
}
case "app":
break;
case "annot":
break;
}
}
function synthesize(ctx: ContextEntry[], term: Term): [Type, ContextEntry[]] {
switch (term.kind) {
case "var": {
const res = lookupTypeVariable(ctx, term.name);
if (!res) throw new Error("wtf?");
return [res, ctx];
}
case "unit":
return [{ kind: "unit" }, ctx];
case "lambda": {
}
case "app":
break;
case "annot": {
// Require that the type exists
if (!isTypeInContext(term.type, ctx))
throw new Error("type doesn't exist");
// Require that the term checks against the type
const [result, outputCtx] = check(ctx, term.term, term.type);
if (!result) throw new Error("invalid annotation: term doesn't check");
return [term.type, outputCtx];
}
}
}
function synthesizeApp(
ctx: ContextEntry[],
funcType: Type,
term: Term
): [Type, ContextEntry[]] {}