A categorical programming language
修订版 | 93e74726ee3198bf643e3348c10f3b064ef4f16e (tree) |
---|---|
时间 | 2022-04-07 13:47:18 |
作者 | Corbin <cds@corb...> |
Commiter | Corbin |
Improve the JIT merge points.
The generated JIT bridges are much nicer. There's still a lot of
typechecking, though.
@@ -5,7 +5,7 @@ import sys | ||
5 | 5 | movelist = sys.argv[-2] |
6 | 6 | jelly = sys.argv[-1] |
7 | 7 | timeout = 5 |
8 | -difficulty = 10 | |
8 | +difficulty = 15 | |
9 | 9 | |
10 | 10 | with open("test_canonical.json", "rb") as handle: |
11 | 11 | testCases = json.load(handle) |
@@ -33,8 +33,8 @@ in | ||
33 | 33 | pypyPackages.pytest libffi |
34 | 34 | ]; |
35 | 35 | |
36 | - JELLY_PATH = "${jelly}/bin/jelly"; | |
37 | - MOVELIST_PATH = "${movelist}/bin/movelist"; | |
36 | + # JELLY_PATH = "${jelly}/bin/jelly"; | |
37 | + # MOVELIST_PATH = "${movelist}/bin/movelist"; | |
38 | 38 | |
39 | 39 | buildPhase = '' |
40 | 40 | source $stdenv/setup |
@@ -1,7 +1,7 @@ | ||
1 | 1 | import math |
2 | 2 | |
3 | -from rpython.rlib.jit import JitDriver, isconstant, we_are_jitted | |
4 | -from rpython.rlib.rbigint import rbigint | |
3 | +from rpython.rlib.jit import JitDriver, isconstant, promote, we_are_jitted | |
4 | +# from rpython.rlib.rbigint import rbigint | |
5 | 5 | |
6 | 6 | |
7 | 7 | class TypeFail(Exception): |
@@ -46,7 +46,7 @@ class N(Element): | ||
46 | 46 | _immutable_ = True |
47 | 47 | def __init__(self, bi): self._bi = bi |
48 | 48 | def n(self): return self._bi |
49 | - def asStr(self): return self._bi.str() | |
49 | + def asStr(self): return "%d" % self._bi | |
50 | 50 | |
51 | 51 | class F(Element): |
52 | 52 | _immutable_ = True |
@@ -106,7 +106,10 @@ class H(Element): | ||
106 | 106 | self._f = f |
107 | 107 | self._x = x |
108 | 108 | def apply(self, y): |
109 | - return self._f.run(P(self._x, y)) | |
109 | + # Defunctionalize by assuming that f can only take on finitely many | |
110 | + # values. This trick was suggested by cfbolz; they do a similar trick | |
111 | + # in Pycket for similar ends. | |
112 | + return promote(self._f).run(P(self._x, y)) | |
110 | 113 | def asStr(self): |
111 | 114 | return "%s @ %s" % (self._f, self._x.asStr()) |
112 | 115 |
@@ -265,12 +268,12 @@ class Disj(Arrow): | ||
265 | 268 | |
266 | 269 | class Zero(Arrow): |
267 | 270 | _immutable_ = True |
268 | - def run(self, x): return N(rbigint.fromint(0)) | |
271 | + def run(self, x): return N(0) | |
269 | 272 | def types(self, cs): return cs.concrete("1"), cs.concrete("N") |
270 | 273 | |
271 | 274 | class Succ(Arrow): |
272 | 275 | _immutable_ = True |
273 | - def run(self, x): return N(x.n().int_add(1)) | |
276 | + def run(self, x): return N(x.n() + 1) | |
274 | 277 | def types(self, cs): return cs.concrete("N"), cs.concrete("N") |
275 | 278 | |
276 | 279 | pr_driver = JitDriver(name="pr", |
@@ -286,9 +289,9 @@ class PrimRec(Arrow): | ||
286 | 289 | def run(self, x): |
287 | 290 | n = x.n() |
288 | 291 | rv = self._x.run(T()) |
289 | - while n.tobool(): | |
292 | + while n > 0: | |
290 | 293 | pr_driver.jit_merge_point(pr=self, n=n, rv=rv) |
291 | - n = n.int_sub(1) | |
294 | + n -= 1 | |
292 | 295 | rv = self._f.run(rv) |
293 | 296 | return rv |
294 | 297 |
@@ -318,11 +321,10 @@ class Cons(Arrow): | ||
318 | 321 | return cs.functor("pair", [x, xs]), xs |
319 | 322 | |
320 | 323 | fold_driver = JitDriver(name="fold", |
321 | - greens=["fold"], reds=["element"], | |
324 | + greens=["arrow", "fold"], reds="auto", | |
322 | 325 | is_recursive=True) |
323 | 326 | |
324 | 327 | def driveFold(fold, element): |
325 | - fold_driver.jit_merge_point(fold=fold, element=element) | |
326 | 328 | return fold.run(element) |
327 | 329 | |
328 | 330 | class Fold(Arrow): |
@@ -333,7 +335,9 @@ class Fold(Arrow): | ||
333 | 335 | def run(self, x): |
334 | 336 | rv = self._n.run(T()) |
335 | 337 | for e in x.l(): |
336 | - rv = driveFold(self._c, P(e, rv)) | |
338 | + fold_driver.jit_merge_point(arrow=self, fold=self._c) | |
339 | + elt = P(e, rv) | |
340 | + rv = self._c.run(elt) | |
337 | 341 | return rv |
338 | 342 | def types(self, cs): |
339 | 343 | ndom, ncod = self._n.types(cs) |
@@ -4,10 +4,10 @@ from rpython.rlib.rfile import create_popen_file | ||
4 | 4 | |
5 | 5 | from cammylib.parser import parse |
6 | 6 | |
7 | -movelist_path = os.environ["MOVELIST_PATH"] | |
8 | - | |
9 | 7 | def askDjinn(dom, cod): |
10 | 8 | "Synthesize a Cammy expression with the given domain and codomain." |
9 | + | |
10 | + movelist_path = os.environ["MOVELIST_PATH"] | |
11 | 11 | command = "%s '%s' '%s' 1" % (movelist_path, dom.asStr(), cod.asStr()) |
12 | 12 | with create_popen_file(command, "r") as handle: |
13 | 13 | s = handle.read() |
@@ -4,13 +4,13 @@ from rpython.rlib.rfile import create_fdopen_rfile | ||
4 | 4 | |
5 | 5 | from cammylib.parser import parse |
6 | 6 | |
7 | -jelly_path = os.environ["JELLY_PATH"] | |
8 | - | |
9 | 7 | def jellify(sexp): |
10 | 8 | """ |
11 | 9 | Optimize a Cammy expression. |
12 | 10 | """ |
13 | 11 | |
12 | + jelly_path = os.environ["JELLY_PATH"] | |
13 | + | |
14 | 14 | rin, win = os.pipe() |
15 | 15 | rout, wout = os.pipe() |
16 | 16 | # NB: We must close all four pipe FDs in both processes. |
@@ -53,27 +53,22 @@ class Window(object): | ||
53 | 53 | return c1, c2 |
54 | 54 | |
55 | 55 | sample_driver = JitDriver(name="sample", |
56 | - greens=["program"], reds=["x", "y"], | |
56 | + greens=["program"], reds="auto", | |
57 | 57 | is_recursive=True) |
58 | 58 | |
59 | -def sample(program, x, y): | |
60 | - sample_driver.jit_merge_point(program=program, x=x, y=y) | |
61 | - rgb = program.run(P(F(x), F(y))) | |
62 | - r = rgb.first().f() | |
63 | - g = rgb.second().first().f() | |
64 | - b = rgb.second().second().f() | |
65 | - return r, g, b | |
66 | - | |
67 | 59 | offsets = [(0.0, 0.0), (1.0, 1.0), (1.0, -1.0), (-1.0, 1.0), (-1.0, -1.0)] |
68 | 60 | |
69 | 61 | @unroll_safe |
70 | 62 | def multisample(program, radius, x, y): |
71 | 63 | r = g = b = 0.0 |
72 | 64 | for ox, oy in offsets: |
73 | - sr, sg, sb = sample(program, x + radius * ox, y + radius * oy) | |
74 | - r += sr | |
75 | - g += sg | |
76 | - b += sb | |
65 | + sx = x + radius * ox | |
66 | + sy = y + radius * oy | |
67 | + sample_driver.jit_merge_point(program=program) | |
68 | + rgb = program.run(P(F(sx), F(sy))) | |
69 | + r += rgb.first().f() | |
70 | + g += rgb.second().first().f() | |
71 | + b += rgb.second().second().f() | |
77 | 72 | l = len(offsets) |
78 | 73 | return finishChannel(r / l), finishChannel(g / l), finishChannel(b / l) |
79 | 74 |
@@ -45,11 +45,19 @@ def command(hive, code, line): | ||
45 | 45 | arrow = sexp.buildArrow() |
46 | 46 | cs = ConstraintStore() |
47 | 47 | domain, codomain = arrow.types(cs) |
48 | + # If the arrow is polymorphic, monomorphize it. | |
49 | + cs.unify(domain, cs.concrete("1")) | |
48 | 50 | extractor = TypeExtractor(cs, PlaintextTypeFormatter()) |
49 | 51 | if extractor.extract(domain) != "1": |
50 | 52 | print "Arrow is not an element" |
51 | 53 | else: |
52 | 54 | print arrow.run(T()).asStr() |
55 | + elif code == "n": | |
56 | + # Normalize an arrow. | |
57 | + sexp, trail = parse(line) | |
58 | + sexp = sexp.canonicalize(hive) | |
59 | + sexp = jellify(sexp) | |
60 | + print sexp.asStr() | |
53 | 61 | elif code == "d": |
54 | 62 | # Invoke djinn. |
55 | 63 | dom, cod = parseTypes(line) |
@@ -3,12 +3,12 @@ let | ||
3 | 3 | inherit (nixpkgs) pkgs; |
4 | 4 | jelly = (import jelly/Cargo.nix { pkgs = nixpkgs; }).rootCrate.build; |
5 | 5 | movelist = import ./movelist { inherit nixpkgs; }; |
6 | - cammy-comb = import ./cammy-rpy/comb.nix { inherit nixpkgs jelly movelist; }; | |
7 | - cammy-draw = import ./cammy-rpy/draw.nix { inherit nixpkgs jelly movelist; }; | |
8 | - cammy-frame = import ./cammy-rpy/frame.nix { inherit nixpkgs jelly movelist; }; | |
9 | - cammy-repl = import ./cammy-rpy/repl.nix { inherit nixpkgs jelly movelist; }; | |
10 | - cammy-rename = import ./cammy-rpy/rename.nix { inherit nixpkgs jelly movelist; }; | |
11 | - cammy-weave = import ./cammy-rpy/weave.nix { inherit nixpkgs jelly movelist; }; | |
6 | + cammy-comb = import ./cammy-rpy/comb.nix { inherit nixpkgs ; }; | |
7 | + cammy-draw = import ./cammy-rpy/draw.nix { inherit nixpkgs ; }; | |
8 | + cammy-frame = import ./cammy-rpy/frame.nix { inherit nixpkgs ; }; | |
9 | + cammy-repl = import ./cammy-rpy/repl.nix { inherit nixpkgs ; }; | |
10 | + cammy-rename = import ./cammy-rpy/rename.nix { inherit nixpkgs ; }; | |
11 | + cammy-weave = import ./cammy-rpy/weave.nix { inherit nixpkgs ; }; | |
12 | 12 | in pkgs.stdenv.mkDerivation { |
13 | 13 | name = "cammy"; |
14 | 14 | version = "0.2"; |
@@ -32,11 +32,23 @@ in pkgs.stdenv.mkDerivation { | ||
32 | 32 | makeWrapper ${jelly}/bin/jelly $out/bin/cammy-jelly |
33 | 33 | |
34 | 34 | # RPython tools |
35 | - makeWrapper ${cammy-comb}/bin/cammy-comb $out/bin/cammy-comb | |
36 | - makeWrapper ${cammy-draw}/bin/cammy-draw $out/bin/cammy-draw | |
37 | - makeWrapper ${cammy-frame}/bin/cammy-frame $out/bin/cammy-frame | |
38 | - makeWrapper ${cammy-repl}/bin/cammy-repl $out/bin/cammy-repl | |
39 | - makeWrapper ${cammy-rename}/bin/cammy-rename $out/bin/cammy-rename | |
40 | - makeWrapper ${cammy-weave}/bin/cammy-weave $out/bin/cammy-weave | |
35 | + makeWrapper ${cammy-comb}/bin/cammy-comb $out/bin/cammy-comb \ | |
36 | + --set JELLY_PATH "$out/bin/cammy-jelly" \ | |
37 | + --set MOVELIST_PATH "$out/bin/cammy-djinn" | |
38 | + makeWrapper ${cammy-draw}/bin/cammy-draw $out/bin/cammy-draw \ | |
39 | + --set JELLY_PATH "$out/bin/cammy-jelly" \ | |
40 | + --set MOVELIST_PATH "$out/bin/cammy-djinn" | |
41 | + makeWrapper ${cammy-frame}/bin/cammy-frame $out/bin/cammy-frame \ | |
42 | + --set JELLY_PATH "$out/bin/cammy-jelly" \ | |
43 | + --set MOVELIST_PATH "$out/bin/cammy-djinn" | |
44 | + makeWrapper ${cammy-repl}/bin/cammy-repl $out/bin/cammy-repl \ | |
45 | + --set JELLY_PATH "$out/bin/cammy-jelly" \ | |
46 | + --set MOVELIST_PATH "$out/bin/cammy-djinn" | |
47 | + makeWrapper ${cammy-rename}/bin/cammy-rename $out/bin/cammy-rename \ | |
48 | + --set JELLY_PATH "$out/bin/cammy-jelly" \ | |
49 | + --set MOVELIST_PATH "$out/bin/cammy-djinn" | |
50 | + makeWrapper ${cammy-weave}/bin/cammy-weave $out/bin/cammy-weave \ | |
51 | + --set JELLY_PATH "$out/bin/cammy-jelly" \ | |
52 | + --set MOVELIST_PATH "$out/bin/cammy-djinn" | |
41 | 53 | ''; |
42 | 54 | } |
@@ -1,4 +1,8 @@ | ||
1 | -(comp (pair (f/addpair (f/divpair (comp pair/swap f-atan2) (fun/const (f/mulpair f-pi f/2))) (fun/const (comp f/2 f-recip))) (f/mulpair v2/complex/norm (fun/const f/2))) hv2rgb) | |
1 | +(comp | |
2 | + (pair | |
3 | + (f/addpair (comp (comp pair/swap f-atan2) f/radians-to-turns) (fun/const (comp f/2 f-recip))) | |
4 | + (f/mulpair v2/complex/norm (fun/const f/2))) | |
5 | + hv2rgb) | |
2 | 6 | |
3 | 7 | Map a complex number to a color. The magnitude is mapped to luminance and the |
4 | 8 | angle is mapped to hue. |
@@ -0,0 +1,11 @@ | ||
1 | +(comp | |
2 | + (comp | |
3 | + (fractal-membership-color v2/burning-ship nat/9) | |
4 | + (monads/maybe/guard (pair/of nat/lte id (fun/const nat/8)))) | |
5 | + (case | |
6 | + (comp (comp nat/to-f f/radians-to-turns) h2rgb) | |
7 | + (v3/broadcast f-zero))) | |
8 | + | |
9 | +Draw membership for the [Burning Ship | |
10 | +fractal](https://en.wikipedia.org/wiki/Burning_Ship_fractal), a relative of | |
11 | +the Mandelbrot set. |
@@ -1,4 +1,4 @@ | ||
1 | -(comp (fractal-membership-fast v2/burning-ship nat/256) (v3/broadcast (f/subpair (fun/const f-one) id))) | |
1 | +(fractal-membership-fast v2/burning-ship nat/8) | |
2 | 2 | |
3 | 3 | Draw membership for the [Burning Ship |
4 | 4 | fractal](https://en.wikipedia.org/wiki/Burning_Ship_fractal), a relative of |
@@ -1,4 +1,4 @@ | ||
1 | -(comp (fractal-membership v2/burning-ship nat/256) (v3/broadcast (f/subpair (fun/const f-one) id))) | |
1 | +(comp (fractal-membership v2/burning-ship nat/8) (v3/broadcast (f/subpair (fun/const f-one) id))) | |
2 | 2 | |
3 | 3 | Draw membership for the [Burning Ship |
4 | 4 | fractal](https://en.wikipedia.org/wiki/Burning_Ship_fractal), a relative of |
@@ -0,0 +1,3 @@ | ||
1 | +(f/mulpair f/2 f-pi) | |
2 | + | |
3 | +The constant $2\pi$, sometimes called $\tau$. |
@@ -0,0 +1,3 @@ | ||
1 | +(f/divpair id (fun/const f/2pi)) | |
2 | + | |
3 | +Convert radians to turns. |
@@ -1,3 +1,7 @@ | ||
1 | -(comp (comp @0 (pair v2/complex/mag-2 (pair left (comp ignore right)))) bool/pick) | |
1 | +(comp | |
2 | + (comp | |
3 | + @0 | |
4 | + (pair v2/complex/mag-2 (pair left (comp ignore right)))) | |
5 | + bool/pick) | |
2 | 6 | |
3 | 7 | Take a step in an IFS, failing if the step has magnitude 2 or greater. |
@@ -0,0 +1,6 @@ | ||
1 | +(comp | |
2 | + (iter-fractal @0 @1) | |
3 | + (comp (list/filter v2/complex/mag-2) list/len)) | |
4 | + | |
5 | +Like fractal-membership, but just returning the length so that we can | |
6 | +false-color it. |
@@ -1,4 +1,8 @@ | ||
1 | -(comp (iter-fractal-fast @0 @1) (case (fun/const f-one) (fun/const f-zero))) | |
1 | +(comp | |
2 | + (iter-fractal-fast @0 @1) | |
3 | + (case | |
4 | + (v3/broadcast (fun/const f-one)) | |
5 | + (comp (comp nat/to-f f/radians-to-turns) h2rgb))) | |
2 | 6 | |
3 | 7 | Iterate a fractal for a maximum number of steps, and return a value in $[0,1]$ |
4 | 8 | indicating how many steps were taken, with 1 indicating that the fractal did |
@@ -1,4 +1,6 @@ | ||
1 | -(comp (iter-fractal @0 @1) (comp (list/filter v2/complex/mag-2) (comp list/len (f/divpair nat/to-f (fun/const (comp @1 nat/to-f)))))) | |
1 | +(comp | |
2 | + (iter-fractal @0 @1) | |
3 | + (comp (list/filter v2/complex/mag-2) (comp list/len (f/divpair nat/to-f (fun/const (comp @1 nat/to-f)))))) | |
2 | 4 | |
3 | 5 | Measure the degree to which a fractal diverges. Given a maximum number of |
4 | 6 | steps, we iterate the IFS for a fractal in the complex plane until its |
@@ -0,0 +1,7 @@ | ||
1 | +(comp | |
2 | + (comp | |
3 | + fun/app | |
4 | + (pair v2/complex/mag-2 (pair left (comp ignore right)))) | |
5 | + bool/pick) | |
6 | + | |
7 | +Like fractal-maybe, but internal. |
@@ -0,0 +1 @@ | ||
1 | +(monads/iter step-unit step-bind (maybe-step @0)) |
@@ -1,4 +1,8 @@ | ||
1 | -(comp (fun/apppair (fun/const (comp @1 nonempty/unfold)) (pair (comp (fun/const f-zero) pair/dup) @0)) snd) | |
1 | +(comp | |
2 | + (fun/apppair | |
3 | + (fun/const (comp @1 nonempty/unfold)) | |
4 | + (pair (comp (fun/const f-zero) pair/dup) @0)) | |
5 | + snd) | |
2 | 6 | |
3 | 7 | Iterate an [IFS](https://en.wikipedia.org/wiki/Iterated_function_system) for a |
4 | 8 | given number of steps. |
@@ -0,0 +1,5 @@ | ||
1 | +(comp | |
2 | + (pair @0 (pair left (fun/const right))) | |
3 | + bool/pick) | |
4 | + | |
5 | +Do nothing if a value passes a filter, otherwise fail. |
@@ -0,0 +1 @@ | ||
1 | +(comp nat/4 nat/sqr) |
@@ -0,0 +1 @@ | ||
1 | +(comp (pair nat/5 nat/2) nat/exp) |
@@ -0,0 +1 @@ | ||
1 | +(comp nat/2 nat/sqr) |
@@ -1 +1,7 @@ | ||
1 | -(curry (comp (uncurry nat/monus) nat/is_zero)) | |
1 | +(uncurry (pr | |
2 | + (curry (fun/const t)) | |
3 | + (curry (comp | |
4 | + (comp (pair/mapsnd nat/pred-maybe) fun/distribr) | |
5 | + (case fun/app (fun/const f)))))) | |
6 | + | |
7 | +The less-than-or-equal relation on natural numbers. |
@@ -20,6 +20,9 @@ fn load_tree(handle :&mut Read) -> std::io::Result<RecExpr<SymbolLang>> { | ||
20 | 20 | // "dual from X" means that justification X formally dualizes to justify the following rule. For |
21 | 21 | // example, products and sums are dual. |
22 | 22 | |
23 | +// "inverse of X" means that rule X is run in reverse in order to open up further optimization | |
24 | +// opportunities. | |
25 | + | |
23 | 26 | // Rules marked "associative!" can cause explosions. |
24 | 27 | |
25 | 28 | // Rules marked "improvement!" can improve IEEE 754 results in both precision and accuracy, so |
@@ -51,6 +54,8 @@ fn main() -> std::io::Result<()> { | ||
51 | 54 | => "(pair (comp ?f ?j) ?g)"), |
52 | 55 | // Elliott 2013 |
53 | 56 | rw!("pair-precompose"; "(pair (comp ?r ?f) (comp ?r ?g))" => "(comp ?r (pair ?f ?g))"), |
57 | + // inverse of pair-precompose | |
58 | + rw!("pair-precompose-inv"; "(comp ?r (pair ?f ?g))" => "(pair (comp ?r ?f) (comp ?r ?g))"), | |
54 | 59 | // pair-precompose when ?f is id |
55 | 60 | rw!("pair-factor-fst"; "(pair ?r (comp ?r ?g))" => "(comp ?r (pair id ?g))"), |
56 | 61 | // pair-precompose when ?g is id |
@@ -88,6 +93,10 @@ fn main() -> std::io::Result<()> { | ||
88 | 93 | rw!("list-unroll-fold-nil"; "(comp nil (fold ?x ?f))" => "?x"), |
89 | 94 | rw!("list-unroll-fold-cons"; "(comp cons (fold ?x ?f))" => "(comp (pair fst (fold ?x ?f)) ?f)"), |
90 | 95 | |
96 | + // 2 = 1 + 1 | |
97 | + rw!("bool-t-either"; "(comp t either)" => "left"), | |
98 | + rw!("bool-f-either"; "(comp f either)" => "right"), | |
99 | + | |
91 | 100 | // Boolean negation |
92 | 101 | rw!("bool-t-not"; "(comp t not)" => "f"), |
93 | 102 | rw!("bool-f-not"; "(comp f not)" => "t"), |
@@ -122,6 +131,9 @@ fn main() -> std::io::Result<()> { | ||
122 | 131 | rw!("f-one-sign"; "(comp f-one f-sign)" => "t"), |
123 | 132 | rw!("f-zero-sign"; "(comp f-zero f-sign)" => "t"), |
124 | 133 | rw!("f-pi-sign"; "(comp f-pi f-sign)" => "t"), |
134 | + | |
135 | + // IEEE 754 function properties | |
136 | + rw!("f-recip-sign"; "(comp f-recip f-sign)" => "f-sign"), | |
125 | 137 | ]; |
126 | 138 | |
127 | 139 | let tree = load_tree(&mut std::io::stdin())?; |
@@ -4,5 +4,6 @@ | ||
4 | 4 | ["X", "(pair X X)", ["(pair id id)"]], |
5 | 5 | ["(pair X Y)", "(pair Y X)", ["(pair snd fst)"]], |
6 | 6 | ["(pair (hom X Y) X)", "Y", ["(uncurry id)"]], |
7 | - ["1", "2", ["t", "f"]] | |
7 | + ["1", "2", ["t", "f"]], | |
8 | + ["1", "(list X)", ["nil", "(comp ignore nil)"]] | |
8 | 9 | ] |
@@ -3,6 +3,7 @@ | ||
3 | 3 | * : commands |
4 | 4 | * help, describe commands |
5 | 5 | * edit an atom's trail |
6 | + * save a recent REPL line as a new file | |
6 | 7 | * More list manipulations |
7 | 8 | * list/eq : [X × X, 2] → [[X] × [X], 2] |
8 | 9 | * list/zip : [X] × [Y] → [X × Y] |
@@ -33,6 +34,7 @@ | ||
33 | 34 | * Interval type? |
34 | 35 | * Cantor's type of bitstrings: N -> 2 |
35 | 36 | * We have subobjects now, X -> 2 |
37 | + * And finite bitstrings, [2] | |
36 | 38 | * Moore machines: For state type Q and input type S, Q × S -> Q |
37 | 39 | * Moore transducers: [Q × S, Q] -> [Q × S, Q] |
38 | 40 | * Mealy machines: For state type Q, input type S, and output type L, Q × S -> Q × L |
@@ -49,5 +51,15 @@ | ||
49 | 51 | * We now can iter-maybe, short-circuiting evaluation |
50 | 52 | * We need to iter-maybe but also keep track of how many steps were taken |
51 | 53 | * Instead of X -> [N, Y + 1], we need X -> [N, N x (Y + 1)] |
54 | + * It's all built and type-checked, but it doesn't work | |
55 | + * The fractal has type C -> [C, C] where C is complex numbers | |
56 | + * We are currently calling it with 0+0i, which is a family index | |
57 | + * Constant family, constant output | |
58 | + * We need to call it with the input number (easy) and then use internal | |
59 | + logic to call the endomorphism in a loop (hard) | |
52 | 60 | * ulimit jellification? |
53 | 61 | * formal power series N -> Q |
62 | +* Dual numbers: like complex numbers, but different units, multiplication | |
63 | +* CI: automatic generation of demo images | |
64 | + * Would be nice to know how long it takes, too | |
65 | + * Parameterize by number of iterations? |