Last active
January 14, 2026 10:44
-
-
Save LeeeeT/26dcfd2d7cdca271a70561fc9375fb0f to your computer and use it in GitHub Desktop.
k-SIC + universal δ + McCarthy's amb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import itertools | |
| from dataclasses import dataclass | |
| type Name = int | |
| name = itertools.count() | |
| type Label = int | |
| label = itertools.count() | |
| type Pos = Var | Nil | Lam | Sup | Usp | Cob | |
| type Neg = Sub | Era | App | Dup | Udp | Amb | |
| @dataclass(frozen=True) | |
| class Var: | |
| nam: Name | |
| @dataclass(frozen=True) | |
| class Sub: | |
| nam: Name | |
| @dataclass(frozen=True) | |
| class Nil: | |
| pass | |
| @dataclass(frozen=True) | |
| class Era: | |
| pass | |
| @dataclass(frozen=True) | |
| class Lam: | |
| bnd: Name | |
| bod: Name | |
| @dataclass(frozen=True) | |
| class App: | |
| arg: Name | |
| ret: Name | |
| @dataclass(frozen=True) | |
| class Dup: | |
| dpl: Label | |
| dp0: Name | |
| dp1: Name | |
| @dataclass(frozen=True) | |
| class Sup: | |
| spl: Label | |
| sp0: Name | |
| sp1: Name | |
| @dataclass(frozen=True) | |
| class Udp: | |
| ud0: Name | |
| ud1: Name | |
| @dataclass(frozen=True) | |
| class Usp: | |
| us0: Name | |
| us1: Name | |
| @dataclass(frozen=True) | |
| class Amb: | |
| m: Name | |
| a: Name | |
| @dataclass(frozen=True) | |
| class Cob: | |
| m: Name | |
| a: Name | |
| type Rdx = tuple[Name, Name] | |
| @dataclass(frozen=True) | |
| class Net: | |
| book: set[Rdx] | |
| vars: dict[Name, Pos] | |
| subs: dict[Name, Neg] | |
| def empty_net() -> Net: | |
| return Net(set(), {}, {}) | |
| def var(net: Net, nam: Name) -> Name: | |
| var = next(name) | |
| net.vars[var] = Var(nam) | |
| return var | |
| def sub(net: Net, nam: Name) -> Name: | |
| sub = next(name) | |
| net.subs[sub] = Sub(nam) | |
| return sub | |
| def nil(net: Net) -> Name: | |
| nil = next(name) | |
| net.vars[nil] = Nil() | |
| return nil | |
| def era(net: Net) -> Name: | |
| era = next(name) | |
| net.subs[era] = Era() | |
| return era | |
| def lam(net: Net, bnd: Name, bod: Name) -> Name: | |
| lam = next(name) | |
| net.vars[lam] = Lam(bnd, bod) | |
| return lam | |
| def app(net: Net, arg: Name, ret: Name) -> Name: | |
| app = next(name) | |
| net.subs[app] = App(arg, ret) | |
| return app | |
| def dup(net: Net, dpl: Label, dp0: Name, dp1: Name) -> Name: | |
| dup = next(name) | |
| net.subs[dup] = Dup(dpl, dp0, dp1) | |
| return dup | |
| def sup(net: Net, spl: Label, sp0: Name, sp1: Name) -> Name: | |
| sup = next(name) | |
| net.vars[sup] = Sup(spl, sp0, sp1) | |
| return sup | |
| def udp(net: Net, ud0: Name, ud1: Name) -> Name: | |
| udp = next(name) | |
| net.subs[udp] = Udp(ud0, ud1) | |
| return udp | |
| def usp(net: Net, us0: Name, us1: Name) -> Name: | |
| usp = next(name) | |
| net.vars[usp] = Usp(us0, us1) | |
| return usp | |
| def amb(net: Net, m: Name, a: Name) -> Name: | |
| amb = next(name) | |
| net.subs[amb] = Amb(m, a) | |
| return amb | |
| def cob(net: Net, m: Name, a: Name) -> Name: | |
| cob = next(name) | |
| net.vars[cob] = Cob(m, a) | |
| return cob | |
| def wire(net: Net) -> tuple[Name, Name]: | |
| nam = next(name) | |
| return var(net, nam), sub(net, nam) | |
| def show_pos(net: Net, pos: Name) -> str: | |
| match net.vars[pos]: | |
| case Var(nam): | |
| return f"+{nam}" | |
| case Nil(): | |
| return "+_" | |
| case Lam(bnd, bod): | |
| return f"+({show_neg(net, bnd)} {show_pos(net, bod)})" | |
| case Sup(spl, sp0, sp1): | |
| return f"+&{spl}{{{show_pos(net, sp0)} {show_pos(net, sp1)}}}" | |
| case Usp(us0, us1): | |
| return f"+{{{show_pos(net, us0)} {show_pos(net, us1)}}}" | |
| case Cob(cb0, cb1): | |
| return f"+[{show_pos(net, cb0)} {show_pos(net, cb1)}]" | |
| def show_neg(net: Net, neg: Name) -> str: | |
| match net.subs[neg]: | |
| case Sub(nam): | |
| return f"-{nam}" | |
| case Era(): | |
| return "-_" | |
| case App(arg, ret): | |
| return f"-({show_pos(net, arg)} {show_neg(net, ret)})" | |
| case Dup(dpl, dp0, dp1): | |
| return f"-&{dpl}{{{show_neg(net, dp0)} {show_neg(net, dp1)}}}" | |
| case Udp(ud0, ud1): | |
| return f"-{{{show_neg(net, ud0)} {show_neg(net, ud1)}}}" | |
| case Amb(am0, am1): | |
| return f"-[{show_neg(net, am0)} {show_neg(net, am1)}]" | |
| def resolve_pos(net: Net, pos: Name) -> None: | |
| match net.vars[pos]: | |
| case Var(nam) if nam in net.vars: | |
| resolve_pos(net, nam) | |
| net.vars[pos] = net.vars.pop(nam) | |
| case Var(nam): | |
| pass | |
| case Nil(): | |
| pass | |
| case Lam(bnd, bod): | |
| resolve_neg(net, bnd) | |
| resolve_pos(net, bod) | |
| case Sup(spl, sp0, sp1): | |
| resolve_pos(net, sp0) | |
| resolve_pos(net, sp1) | |
| case Usp(us0, us1): | |
| resolve_pos(net, us0) | |
| resolve_pos(net, us1) | |
| case Cob(cb0, cb1): | |
| resolve_pos(net, cb0) | |
| resolve_pos(net, cb1) | |
| def resolve_neg(net: Net, neg: Name) -> None: | |
| match net.subs[neg]: | |
| case Sub(nam) if nam in net.subs: | |
| resolve_neg(net, nam) | |
| net.subs[neg] = net.subs.pop(nam) | |
| case Sub(nam): | |
| pass | |
| case Era(): | |
| pass | |
| case App(arg, ret): | |
| resolve_pos(net, arg) | |
| resolve_neg(net, ret) | |
| case Dup(dpl, dp0, dp1): | |
| resolve_neg(net, dp0) | |
| resolve_neg(net, dp1) | |
| case Udp(ud0, ud1): | |
| resolve_neg(net, ud0) | |
| resolve_neg(net, ud1) | |
| case Amb(am0, am1): | |
| resolve_neg(net, am0) | |
| resolve_neg(net, am1) | |
| def reduce(net: Net) -> int: | |
| itrs = 0 | |
| while net.book: | |
| itrs += 1 | |
| lhs, rhs = net.book.pop() | |
| match net.subs.pop(lhs), net.vars.pop(rhs): | |
| case lhsc, Var(nam) if nam in net.vars: | |
| net.subs[lhs] = lhsc | |
| net.book.add((lhs, nam)) | |
| case lhsc, Var(nam): | |
| net.subs[nam] = lhsc | |
| case Sub(nam), rhsc if nam in net.subs: | |
| net.vars[rhs] = rhsc | |
| net.book.add((nam, rhs)) | |
| case Sub(nam), rhsc: | |
| net.vars[nam] = rhsc | |
| case lhsc, Cob(m, a) if m in net.vars: | |
| net.subs[lhs] = lhsc | |
| x = next(name) | |
| net.vars[x] = net.vars.pop(m) | |
| net.book.add((lhs, x)) | |
| case lhsc, Cob(m, a): | |
| net.subs[lhs] = lhsc | |
| net.book.add((lhs, a)) | |
| case Amb(m, a), rhsc if m in net.subs: | |
| net.vars[rhs] = rhsc | |
| x = next(name) | |
| net.subs[x] = net.subs.pop(m) | |
| net.book.add((x, rhs)) | |
| case Amb(m, a), rhsc: | |
| net.vars[rhs] = rhsc | |
| net.book.add((a, rhs)) | |
| case Era(), Nil(): | |
| pass | |
| case Era(), Lam(bnd, bod): | |
| net.book.add((bnd, nil(net))) | |
| net.book.add((era(net), bod)) | |
| case Era(), Sup(spl, sp0, sp1): | |
| net.book.add((era(net), sp0)) | |
| net.book.add((era(net), sp1)) | |
| case Era(), Usp(us0, us1): | |
| net.book.add((era(net), us0)) | |
| net.book.add((era(net), us1)) | |
| case App(arg, ret), Nil(): | |
| net.book.add((era(net), arg)) | |
| net.book.add((ret, nil(net))) | |
| case App(arg, ret), Lam(bnd, bod): | |
| net.book.add((bnd, arg)) | |
| net.book.add((ret, bod)) | |
| case App(arg, ret), Sup(spl, sp0, sp1): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| net.book.add((dup(net, spl, an, bn), arg)) | |
| net.book.add((ret, sup(net, spl, cp, dp))) | |
| net.book.add((app(net, ap, cn), sp0)) | |
| net.book.add((app(net, bp, dn), sp1)) | |
| case App(arg, ret), Usp(us0, us1): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| lab = next(label) | |
| net.book.add((dup(net, lab, an, bn), arg)) | |
| net.book.add((ret, sup(net, lab, cp, dp))) | |
| net.book.add((app(net, ap, cn), us0)) | |
| net.book.add((app(net, bp, dn), us1)) | |
| case Dup(dpl, dp0, dp1), Nil(): | |
| net.book.add((dp0, nil(net))) | |
| net.book.add((dp1, nil(net))) | |
| case Dup(dpl, dp0, dp1), Lam(bnd, bod): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| net.book.add((dp0, lam(net, an, bp))) | |
| net.book.add((dp1, lam(net, cn, dp))) | |
| net.book.add((bnd, sup(net, dpl, ap, cp))) | |
| net.book.add((dup(net, dpl, bn, dn), bod)) | |
| case Dup(dpl, dp0, dp1), Sup(spl, sp0, sp1) if dpl == spl: | |
| net.book.add((dp0, sp0)) | |
| net.book.add((dp1, sp1)) | |
| case Dup(dpl, dp0, dp1), Sup(spl, sp0, sp1): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| net.book.add((dp0, sup(net, spl, ap, bp))) | |
| net.book.add((dp1, sup(net, spl, cp, dp))) | |
| net.book.add((dup(net, dpl, an, cn), sp0)) | |
| net.book.add((dup(net, dpl, bn, dn), sp1)) | |
| case Dup(dpl, dp0, dp1), Usp(us0, us1): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| net.book.add((dp0, usp(net, ap, bp))) | |
| net.book.add((dp1, usp(net, cp, dp))) | |
| net.book.add((dup(net, dpl, an, cn), us0)) | |
| net.book.add((dup(net, dpl, bn, dn), us1)) | |
| case Udp(ud0, ud1), Nil(): | |
| net.book.add((ud0, nil(net))) | |
| net.book.add((ud1, nil(net))) | |
| case Udp(ud0, ud1), Lam(bnd, bod): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| lab = next(label) | |
| net.book.add((ud0, lam(net, an, bp))) | |
| net.book.add((ud1, lam(net, cn, dp))) | |
| net.book.add((bnd, sup(net, lab, ap, cp))) | |
| net.book.add((dup(net, lab, bn, dn), bod)) | |
| case Udp(ud0, ud1), Sup(spl, sp0, sp1): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| net.book.add((ud0, sup(net, spl, ap, bp))) | |
| net.book.add((ud1, sup(net, spl, cp, dp))) | |
| net.book.add((udp(net, an, cn), sp0)) | |
| net.book.add((udp(net, bn, dn), sp1)) | |
| case Udp(ud0, ud1), Usp(us0, us1): | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| cp, cn = wire(net) | |
| dp, dn = wire(net) | |
| net.book.add((ud0, usp(net, ap, bp))) | |
| net.book.add((ud1, usp(net, cp, dp))) | |
| net.book.add((udp(net, an, cn), us0)) | |
| net.book.add((udp(net, bn, dn), us1)) | |
| return itrs | |
| def print_state(net: Net, root: Name, *, heap: bool = False) -> None: | |
| print("ROOT:") | |
| print(f" {show_pos(net, root)}") | |
| print() | |
| print("BOOK:") | |
| for lhs, rhs in net.book: | |
| print(f" {show_neg(net, lhs)} ⋈ {show_pos(net, rhs)}") | |
| if heap: | |
| print() | |
| print("VARS:") | |
| for nam in net.vars: | |
| print(f" {nam} = {show_pos(net, nam)}") | |
| print() | |
| print("SUBS:") | |
| for nam in net.subs: | |
| print(f" {nam} = {show_neg(net, nam)}") | |
| def print_reduction(net: Net, root: Name, *, heap: bool = False) -> None: | |
| print("=" * 30) | |
| print("=", "INITIAL".center(26), "=") | |
| print("=" * 30) | |
| print() | |
| print_state(net, root, heap=heap) | |
| print() | |
| print("=" * 30) | |
| print("=", "NORMALIZED".center(26), "=") | |
| print("=" * 30) | |
| print() | |
| itrs = reduce(net) | |
| resolve_pos(net, root) | |
| print_state(net, root, heap=heap) | |
| print() | |
| print(f"ITRS: {itrs}") | |
| def mk_app(net: Net, fun: Name, arg: Name) -> Name: | |
| rp, rn = wire(net) | |
| net.book.add((app(net, arg, rn), fun)) | |
| return rp | |
| def mk_dup(net: Net, x: Name, lab: Label | None = None) -> tuple[Name, Name]: | |
| if lab is None: | |
| lab = next(label) | |
| x0p, x0n = wire(net) | |
| x1p, x1n = wire(net) | |
| net.book.add((dup(net, lab, x0n, x1n), x)) | |
| return x0p, x1p | |
| def mk_udp(net: Net, x: Name) -> tuple[Name, Name]: | |
| x0p, x0n = wire(net) | |
| x1p, x1n = wire(net) | |
| net.book.add((udp(net, x0n, x1n), x)) | |
| return x0p, x1p | |
| def mk_amb(net: Net, fst: Name, snd: Name) -> tuple[Name, Name]: | |
| xp, xn = wire(net) | |
| yp, yn = wire(net) | |
| net.book.add((amb(net, xn, yn), fst)) | |
| net.book.add((amb(net, xn, yn), snd)) | |
| return xp, yp | |
| # λt.λf.t | |
| def mk_true(net: Net) -> Name: | |
| tp, tn = wire(net) | |
| return lam(net, tn, lam(net, era(net), tp)) | |
| # λt.λf.f | |
| def mk_false(net: Net) -> Name: | |
| fp, fn = wire(net) | |
| return lam(net, era(net), lam(net, fn, fp)) | |
| # λb.(b true false) | |
| def mk_bool_eta_expand(net: Net) -> Name: | |
| bp, bn = wire(net) | |
| return lam(net, bn, mk_app(net, mk_app(net, bp, mk_true(net)), mk_false(net))) | |
| # λa.λb.λt.λf.(a t (b t f)) | |
| def mk_or(net: Net) -> Name: | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| tp, tn = wire(net) | |
| fp, fn = wire(net) | |
| t0, t1 = mk_udp(net, tp) | |
| at = mk_app(net, ap, t0) | |
| btf = mk_app(net, mk_app(net, bp, t1), fp) | |
| ret = mk_app(net, at, btf) | |
| return lam(net, an, lam(net, bn, lam(net, tn, lam(net, fn, ret)))) | |
| # parallel or | |
| # λa.λb. (x,y)=amb(a,b); (or x y) | |
| def mk_por(net: Net) -> Name: | |
| ap, an = wire(net) | |
| bp, bn = wire(net) | |
| x, y = mk_amb(net, ap, bp) | |
| ret = mk_app(net, mk_app(net, mk_or(net), x), y) | |
| return lam(net, an, lam(net, bn, ret)) | |
| # A or TRUE, where A is stuck | |
| # {a0,a1}=a0; (or a1 true) | |
| def mk_test_or(net: Net) -> Name: | |
| a0p, a0n = wire(net) | |
| a1p, a1n = wire(net) | |
| net.book.add((udp(net, a0n, a1n), a0p)) | |
| return mk_app(net, mk_app(net, mk_or(net), a1p), mk_true(net)) | |
| # A por TRUE, where A is stuck | |
| # {a0,a1}=a0; (por a1 true) | |
| def mk_test_por(net: Net) -> Name: | |
| a0p, a0n = wire(net) | |
| a1p, a1n = wire(net) | |
| net.book.add((udp(net, a0n, a1n), a0p)) | |
| return mk_app(net, mk_app(net, mk_por(net), a1p), mk_true(net)) | |
| def main() -> None: | |
| net = empty_net() | |
| # root = mk_app(net, mk_bool_eta_expand(net), mk_test_or(net)) # expect a dangling wire | |
| root = mk_app(net, mk_bool_eta_expand(net), mk_test_por(net)) # expect TRUE | |
| print_reduction(net, root) | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment