progress
This commit is contained in:
parent
e985f35185
commit
8ce0d1fcb6
5 changed files with 216 additions and 81 deletions
57
bidir/bidir.ts
Normal file
57
bidir/bidir.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
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[]] {}
|
18
bidir/contexts.ts
Normal file
18
bidir/contexts.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// 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;
|
||||||
|
}
|
42
bidir/data.ts
Normal file
42
bidir/data.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* 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 };
|
5
extraexercises.agda
Normal file
5
extraexercises.agda
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module extraexercises where
|
||||||
|
|
||||||
|
open import Data.Nat
|
||||||
|
open import Relation.Binary.PropositionalEquality as Eq
|
||||||
|
open Eq.≡-Reasoning
|
175
hwk1.typ
175
hwk1.typ
|
@ -1,26 +1,36 @@
|
||||||
|
#set document(title: "Homework 1", author: "Michael Zhang <zhan4854@umn.edu>")
|
||||||
#set page("us-letter")
|
#set page("us-letter")
|
||||||
#import "@preview/prooftrees:0.1.0": *
|
#import "@preview/prooftrees:0.1.0": *
|
||||||
|
|
||||||
|
= Homework 1
|
||||||
|
|
||||||
|
Michael Zhang \<zhan4854\@umn.edu\>
|
||||||
|
|
||||||
|
|
||||||
#let c(body) = {
|
#let c(body) = {
|
||||||
set text(gray)
|
set text(gray)
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
= Problem 1
|
$#math.op("f")\(x)$
|
||||||
|
|
||||||
|
== Problem 1
|
||||||
|
|
||||||
|
$top : "Set"$
|
||||||
|
|
||||||
|
$"case"_top$
|
||||||
|
|
||||||
#c[Define `funsplit` in terms of `apply`.]
|
#c[Define `funsplit` in terms of `apply`.]
|
||||||
|
|
||||||
$ "funsplit"(f, d) &equiv d("apply"(f, (x) x)) $
|
$ "funsplit"(f, d) &equiv d((x) "apply"(f, x)) $
|
||||||
|
|
||||||
In the case of $f = lambda b$ the following evaluation occurs:
|
In the case of $f = lambda b$ the following evaluation occurs:
|
||||||
|
|
||||||
$ "funsplit"(lambda b, d) &equiv d( "apply"(lambda b, (x) x)) \
|
$ "funsplit"(lambda b, d) &equiv d((x) "apply"(lambda b, x)) \
|
||||||
&equiv d(((x)x)(b)) \
|
&equiv d((x) (b(x))) \
|
||||||
&equiv d(b) $
|
&equiv d(b) $
|
||||||
|
|
||||||
NOTE: Is it "cheating" in some sense, to use the identity abstraction $(x) x$ in the place of the last parameter to $"apply"$?
|
== Problem 2
|
||||||
|
|
||||||
= Problem 2
|
|
||||||
|
|
||||||
#c[Assuming that you have Eq sets at your disposal, use only rules (without appealing to the One True Language) to prove:
|
#c[Assuming that you have Eq sets at your disposal, use only rules (without appealing to the One True Language) to prove:
|
||||||
|
|
||||||
|
@ -91,112 +101,115 @@ $ #tree(
|
||||||
) $
|
) $
|
||||||
|
|
||||||
$ #tree(
|
$ #tree(
|
||||||
axi[$x = y in NN [x in NN, y in NN]$],
|
axi[$x in NN$],
|
||||||
uni(right_label: "(3, 6)")[$"suc"(x) = "suc"(y) in NN [x in NN, y 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(
|
$ #pad(left: -4em, tree(
|
||||||
axi(pad(bottom: .2em, [
|
axi(pad(bottom: .2em, [
|
||||||
$x in NN$ \
|
$x in NN$ \
|
||||||
$"Eq"(NN, "natrec"(n, 0, (u, v) "suc"(v)), n) "set" [n in NN]$ \
|
$"Eq"(NN, "natrec"(n, 0, (u, v) "suc"(v)), n) "set" [n in NN]$ \
|
||||||
$"eq"_"0" in "Eq"(NN, "natrec"(0, 0, (u, v) "suc"(v)), 0)$ \
|
$"eq"_"0" in "Eq"(NN, "natrec"(0, 0, (u, v) "suc"(v)), 0)$ \
|
||||||
$"eq"_"suc" (x, y) in "Eq"(NN, "natrec"("suc"(x), 0, (u, v) "suc"(v)), "suc"(x)) [x in NN, y in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x)]$ \
|
$"eq"_"suc" (x, y) in "Eq"(NN, "natrec"("suc"(x), 0, (u, v) "suc"(v)), "suc"(x)) [x in NN, y in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x)]$ \
|
||||||
])),
|
])),
|
||||||
uni[$"natrec"(x, "eq"_"0", "eq"_"suc") in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x)$],
|
uni(right_label: "(7, 9, 10)")[$"natrec"(x, "eq"_"0", "eq"_"suc") in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x)$],
|
||||||
) $
|
)) $
|
||||||
|
|
||||||
#tree(
|
#tree(
|
||||||
axi[$"natrec"(x, "eq"_"0", "eq"_"suc") in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x) [x in NN]$],
|
axi[$"natrec"(x, "eq"_"0", "eq"_"suc") in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x) [x in NN]$],
|
||||||
uni(right_label: "(5)")[$"natrec"(x, 0, (u, v) "suc"(v)) = x in NN [x in NN]$],
|
uni(right_label: "(5, 11)")[$"natrec"(x, 0, (u, v) "suc"(v)) = x in NN [x in NN]$],
|
||||||
uni(right_label: [#sym.plus.circle])[$plus.circle(x, 0) = x in NN [x in NN]$],
|
uni(right_label: [#sym.plus.circle])[$plus.circle(x, 0) = x in NN [x in NN]$],
|
||||||
)
|
)
|
||||||
|
|
||||||
#pagebreak()
|
// #pagebreak()
|
||||||
|
|
||||||
Then, we can use this:
|
// Then, we can use this:
|
||||||
|
|
||||||
#set math.equation(numbering: none)
|
// #set math.equation(numbering: none)
|
||||||
|
|
||||||
#tree(
|
// #tree(
|
||||||
axi[$0 in NN$],
|
// axi[$0 in NN$],
|
||||||
uni(right_label: "(1)")[$0 = 0 in NN$],
|
// uni(right_label: "(1)")[$0 = 0 in NN$],
|
||||||
uni(right_label: "(3)")[$"eq"_0 in "Eq"(NN, 0, 0)$],
|
// uni(right_label: "(3)")[$"eq"_0 in "Eq"(NN, 0, 0)$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
Using $C(x) = NN$ and the substitution-in-elements rule, we can prove that suc distributes over equivalence:
|
// Using $C(x) = NN$ and the substitution-in-elements rule, we can prove that suc distributes over equivalence:
|
||||||
|
|
||||||
#tree(
|
// #tree(
|
||||||
axi[$"suc"(x) in C(x) [x in NN]$],
|
// axi[$"suc"(x) in C(x) [x in NN]$],
|
||||||
axi[$x = y in NN$],
|
// axi[$x = y in NN$],
|
||||||
bin[$"suc"(x) = "suc"(y) in NN$],
|
// bin[$"suc"(x) = "suc"(y) in NN$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
Then, convert this to Eq:
|
// Then, convert this to Eq:
|
||||||
|
|
||||||
#tree(
|
// #tree(
|
||||||
axi[$"suc"(x) = "suc"(y) in NN$],
|
// axi[$"suc"(x) = "suc"(y) in NN$],
|
||||||
axi[$x = y in NN$],
|
// axi[$x = y in NN$],
|
||||||
bin[$"eq"_"xy-suc" in "Eq"(NN, "suc"(x), "suc"(y))$],
|
// bin[$"eq"_"xy-suc" in "Eq"(NN, "suc"(x), "suc"(y))$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
We can form a lambda term over eq objects using $lambda$-introduction:
|
// We can form a lambda term over eq objects using $lambda$-introduction:
|
||||||
|
|
||||||
#tree(
|
// #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]$],
|
// 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))$],
|
// uni[$lambda(("eq"_"xy") "eq"_"xy-suc") in "Eq"(NN, x, y) arrow.r "Eq"(NN, "suc"(x), "suc"(y))$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
This gives us what we need to perform induction over nats:
|
// This gives us what we need to perform induction over nats:
|
||||||
|
|
||||||
#tree(
|
// #tree(
|
||||||
axi[$"natrec"(x, "eq"_0, (u, v) "apply"(lambda(("eq"_"xy") "eq"_"xy-suc"), v)) [x in NN]$],
|
// axi[$"natrec"(x, "eq"_0, (u, v) "apply"(lambda(("eq"_"xy") "eq"_"xy-suc"), v)) [x in NN]$],
|
||||||
uni[]
|
// uni[]
|
||||||
)
|
// )
|
||||||
|
|
||||||
#tree(
|
// #tree(
|
||||||
axi[$"i'm fucking stupid" equiv (x) "natrec"(x, 0, (u, v) "suc"(v))$],
|
// axi[$"i'm fucking stupid" equiv (x) "natrec"(x, 0, (u, v) "suc"(v))$],
|
||||||
uni[],
|
// uni[],
|
||||||
)
|
// )
|
||||||
|
|
||||||
#tree(
|
// #tree(
|
||||||
axi[$"eq" in "Eq"(NN, "natrec"(x, 0, (u, v) "suc"(v)), x) [x in NN]$],
|
// 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[$"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]$],
|
// uni(right_label: "macro")[$plus.circle(x, 0) = x in NN [x in NN]$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
---
|
// ---
|
||||||
#pagebreak()
|
// #pagebreak()
|
||||||
|
|
||||||
#{
|
// #{
|
||||||
let split1 = [$"natrec" (x, 0, (u, v) "suc"(v))$]
|
// let split1 = [$"natrec" (x, 0, (u, v) "suc"(v))$]
|
||||||
|
|
||||||
tree(
|
// tree(
|
||||||
axi[$"natrec"(x, "refl", (u, v) ("ap" v)) [x in NN]$],
|
// axi[$"natrec"(x, "refl", (u, v) ("ap" v)) [x in NN]$],
|
||||||
uni[$split1 equiv x in NN [x in NN]$],
|
// uni[$split1 equiv x in NN [x in NN]$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
tree(
|
// tree(
|
||||||
// axi[$c in "Eq"(NN, split1, 0), x)$],
|
// // axi[$c in "Eq"(NN, split1, 0), x)$],
|
||||||
axi[$split1 equiv x in NN [x in NN]$],
|
// axi[$split1 equiv x in NN [x in NN]$],
|
||||||
uni(right_label: "macro")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
|
// uni(right_label: "macro")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
tree(
|
// tree(
|
||||||
axi[$c in "Eq"(NN, plus.circle(x, 0), x)$],
|
// axi[$c in "Eq"(NN, plus.circle(x, 0), x)$],
|
||||||
uni[$plus.circle(x, 0) equiv x in NN [x in NN]$],
|
// uni[$plus.circle(x, 0) equiv x in NN [x in NN]$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
tree(
|
// tree(
|
||||||
axi[$plus.circle(x, 0) equiv split1 [x in NN]$],
|
// axi[$plus.circle(x, 0) equiv split1 [x in NN]$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
tree(
|
// tree(
|
||||||
axi[$split1 equiv x [x in NN]$],
|
// axi[$split1 equiv x [x in NN]$],
|
||||||
)
|
// )
|
||||||
|
|
||||||
tree(
|
// tree(
|
||||||
axi[$plus.circle(x, 0) equiv split1 [x in NN]$],
|
// axi[$plus.circle(x, 0) equiv split1 [x in NN]$],
|
||||||
axi[$split1 equiv x [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]$],
|
// bin(right_label: "trans")[$plus.circle(x, 0) equiv x in NN [x in NN]$],
|
||||||
)
|
// )
|
||||||
}
|
// }
|
Loading…
Reference in a new issue