• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-cqtcocoa誰得pythonphprubygameguibathyscaphec翻訳計画中(planning stage)omegatframeworktwittertestdomvb.netdirectxbtronarduinopreviewerゲームエンジン

A categorical programming language


Commit MetaInfo

修订版93e74726ee3198bf643e3348c10f3b064ef4f16e (tree)
时间2022-04-07 13:47:18
作者Corbin <cds@corb...>
CommiterCorbin

Log Message

Improve the JIT merge points.

The generated JIT bridges are much nicer. There's still a lot of
typechecking, though.

更改概述

差异

--- a/accept-jelly.py
+++ b/accept-jelly.py
@@ -5,7 +5,7 @@ import sys
55 movelist = sys.argv[-2]
66 jelly = sys.argv[-1]
77 timeout = 5
8-difficulty = 10
8+difficulty = 15
99
1010 with open("test_canonical.json", "rb") as handle:
1111 testCases = json.load(handle)
--- a/cammy-rpy/builder.nix
+++ b/cammy-rpy/builder.nix
@@ -33,8 +33,8 @@ in
3333 pypyPackages.pytest libffi
3434 ];
3535
36- JELLY_PATH = "${jelly}/bin/jelly";
37- MOVELIST_PATH = "${movelist}/bin/movelist";
36+ # JELLY_PATH = "${jelly}/bin/jelly";
37+ # MOVELIST_PATH = "${movelist}/bin/movelist";
3838
3939 buildPhase = ''
4040 source $stdenv/setup
--- a/cammy-rpy/cammylib/arrows.py
+++ b/cammy-rpy/cammylib/arrows.py
@@ -1,7 +1,7 @@
11 import math
22
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
55
66
77 class TypeFail(Exception):
@@ -46,7 +46,7 @@ class N(Element):
4646 _immutable_ = True
4747 def __init__(self, bi): self._bi = bi
4848 def n(self): return self._bi
49- def asStr(self): return self._bi.str()
49+ def asStr(self): return "%d" % self._bi
5050
5151 class F(Element):
5252 _immutable_ = True
@@ -106,7 +106,10 @@ class H(Element):
106106 self._f = f
107107 self._x = x
108108 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))
110113 def asStr(self):
111114 return "%s @ %s" % (self._f, self._x.asStr())
112115
@@ -265,12 +268,12 @@ class Disj(Arrow):
265268
266269 class Zero(Arrow):
267270 _immutable_ = True
268- def run(self, x): return N(rbigint.fromint(0))
271+ def run(self, x): return N(0)
269272 def types(self, cs): return cs.concrete("1"), cs.concrete("N")
270273
271274 class Succ(Arrow):
272275 _immutable_ = True
273- def run(self, x): return N(x.n().int_add(1))
276+ def run(self, x): return N(x.n() + 1)
274277 def types(self, cs): return cs.concrete("N"), cs.concrete("N")
275278
276279 pr_driver = JitDriver(name="pr",
@@ -286,9 +289,9 @@ class PrimRec(Arrow):
286289 def run(self, x):
287290 n = x.n()
288291 rv = self._x.run(T())
289- while n.tobool():
292+ while n > 0:
290293 pr_driver.jit_merge_point(pr=self, n=n, rv=rv)
291- n = n.int_sub(1)
294+ n -= 1
292295 rv = self._f.run(rv)
293296 return rv
294297
@@ -318,11 +321,10 @@ class Cons(Arrow):
318321 return cs.functor("pair", [x, xs]), xs
319322
320323 fold_driver = JitDriver(name="fold",
321- greens=["fold"], reds=["element"],
324+ greens=["arrow", "fold"], reds="auto",
322325 is_recursive=True)
323326
324327 def driveFold(fold, element):
325- fold_driver.jit_merge_point(fold=fold, element=element)
326328 return fold.run(element)
327329
328330 class Fold(Arrow):
@@ -333,7 +335,9 @@ class Fold(Arrow):
333335 def run(self, x):
334336 rv = self._n.run(T())
335337 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)
337341 return rv
338342 def types(self, cs):
339343 ndom, ncod = self._n.types(cs)
--- a/cammy-rpy/cammylib/djinn.py
+++ b/cammy-rpy/cammylib/djinn.py
@@ -4,10 +4,10 @@ from rpython.rlib.rfile import create_popen_file
44
55 from cammylib.parser import parse
66
7-movelist_path = os.environ["MOVELIST_PATH"]
8-
97 def askDjinn(dom, cod):
108 "Synthesize a Cammy expression with the given domain and codomain."
9+
10+ movelist_path = os.environ["MOVELIST_PATH"]
1111 command = "%s '%s' '%s' 1" % (movelist_path, dom.asStr(), cod.asStr())
1212 with create_popen_file(command, "r") as handle:
1313 s = handle.read()
--- a/cammy-rpy/cammylib/jelly.py
+++ b/cammy-rpy/cammylib/jelly.py
@@ -4,13 +4,13 @@ from rpython.rlib.rfile import create_fdopen_rfile
44
55 from cammylib.parser import parse
66
7-jelly_path = os.environ["JELLY_PATH"]
8-
97 def jellify(sexp):
108 """
119 Optimize a Cammy expression.
1210 """
1311
12+ jelly_path = os.environ["JELLY_PATH"]
13+
1414 rin, win = os.pipe()
1515 rout, wout = os.pipe()
1616 # NB: We must close all four pipe FDs in both processes.
--- a/cammy-rpy/draw.py
+++ b/cammy-rpy/draw.py
@@ -53,27 +53,22 @@ class Window(object):
5353 return c1, c2
5454
5555 sample_driver = JitDriver(name="sample",
56- greens=["program"], reds=["x", "y"],
56+ greens=["program"], reds="auto",
5757 is_recursive=True)
5858
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-
6759 offsets = [(0.0, 0.0), (1.0, 1.0), (1.0, -1.0), (-1.0, 1.0), (-1.0, -1.0)]
6860
6961 @unroll_safe
7062 def multisample(program, radius, x, y):
7163 r = g = b = 0.0
7264 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()
7772 l = len(offsets)
7873 return finishChannel(r / l), finishChannel(g / l), finishChannel(b / l)
7974
--- a/cammy-rpy/repl.py
+++ b/cammy-rpy/repl.py
@@ -45,11 +45,19 @@ def command(hive, code, line):
4545 arrow = sexp.buildArrow()
4646 cs = ConstraintStore()
4747 domain, codomain = arrow.types(cs)
48+ # If the arrow is polymorphic, monomorphize it.
49+ cs.unify(domain, cs.concrete("1"))
4850 extractor = TypeExtractor(cs, PlaintextTypeFormatter())
4951 if extractor.extract(domain) != "1":
5052 print "Arrow is not an element"
5153 else:
5254 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()
5361 elif code == "d":
5462 # Invoke djinn.
5563 dom, cod = parseTypes(line)
--- a/default.nix
+++ b/default.nix
@@ -3,12 +3,12 @@ let
33 inherit (nixpkgs) pkgs;
44 jelly = (import jelly/Cargo.nix { pkgs = nixpkgs; }).rootCrate.build;
55 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 ; };
1212 in pkgs.stdenv.mkDerivation {
1313 name = "cammy";
1414 version = "0.2";
@@ -32,11 +32,23 @@ in pkgs.stdenv.mkDerivation {
3232 makeWrapper ${jelly}/bin/jelly $out/bin/cammy-jelly
3333
3434 # 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"
4153 '';
4254 }
--- a/hive/complex-graph.cammy
+++ b/hive/complex-graph.cammy
@@ -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)
26
37 Map a complex number to a color. The magnitude is mapped to luminance and the
48 angle is mapped to hue.
--- /dev/null
+++ b/hive/demo/burning-ship-color.cammy
@@ -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.
--- a/hive/demo/burning-ship-fast.cammy
+++ b/hive/demo/burning-ship-fast.cammy
@@ -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)
22
33 Draw membership for the [Burning Ship
44 fractal](https://en.wikipedia.org/wiki/Burning_Ship_fractal), a relative of
--- a/hive/demo/burning-ship.cammy
+++ b/hive/demo/burning-ship.cammy
@@ -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)))
22
33 Draw membership for the [Burning Ship
44 fractal](https://en.wikipedia.org/wiki/Burning_Ship_fractal), a relative of
--- /dev/null
+++ b/hive/f/2pi.cammy
@@ -0,0 +1,3 @@
1+(f/mulpair f/2 f-pi)
2+
3+The constant $2\pi$, sometimes called $\tau$.
--- /dev/null
+++ b/hive/f/radians-to-turns.cammy
@@ -0,0 +1,3 @@
1+(f/divpair id (fun/const f/2pi))
2+
3+Convert radians to turns.
--- a/hive/fractal-maybe.cammy
+++ b/hive/fractal-maybe.cammy
@@ -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)
26
37 Take a step in an IFS, failing if the step has magnitude 2 or greater.
--- /dev/null
+++ b/hive/fractal-membership-color.cammy
@@ -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.
--- a/hive/fractal-membership-fast.cammy
+++ b/hive/fractal-membership-fast.cammy
@@ -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)))
26
37 Iterate a fractal for a maximum number of steps, and return a value in $[0,1]$
48 indicating how many steps were taken, with 1 indicating that the fractal did
--- a/hive/fractal-membership.cammy
+++ b/hive/fractal-membership.cammy
@@ -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))))))
24
35 Measure the degree to which a fractal diverges. Given a maximum number of
46 steps, we iterate the IFS for a fractal in the complex plane until its
--- /dev/null
+++ b/hive/int-fractal-maybe.cammy
@@ -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.
--- /dev/null
+++ b/hive/int-step-iter.cammy
@@ -0,0 +1 @@
1+(monads/iter step-unit step-bind (maybe-step @0))
--- a/hive/iter-fractal.cammy
+++ b/hive/iter-fractal.cammy
@@ -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)
26
37 Iterate an [IFS](https://en.wikipedia.org/wiki/Iterated_function_system) for a
48 given number of steps.
--- /dev/null
+++ b/hive/monads/maybe/guard.cammy
@@ -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.
--- /dev/null
+++ b/hive/nat/16.cammy
@@ -0,0 +1 @@
1+(comp nat/4 nat/sqr)
--- /dev/null
+++ b/hive/nat/32.cammy
@@ -0,0 +1 @@
1+(comp (pair nat/5 nat/2) nat/exp)
--- /dev/null
+++ b/hive/nat/4.cammy
@@ -0,0 +1 @@
1+(comp nat/2 nat/sqr)
--- a/hive/nat/lte.cammy
+++ b/hive/nat/lte.cammy
@@ -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.
--- a/jelly/src/main.rs
+++ b/jelly/src/main.rs
@@ -20,6 +20,9 @@ fn load_tree(handle :&mut Read) -> std::io::Result<RecExpr<SymbolLang>> {
2020 // "dual from X" means that justification X formally dualizes to justify the following rule. For
2121 // example, products and sums are dual.
2222
23+// "inverse of X" means that rule X is run in reverse in order to open up further optimization
24+// opportunities.
25+
2326 // Rules marked "associative!" can cause explosions.
2427
2528 // Rules marked "improvement!" can improve IEEE 754 results in both precision and accuracy, so
@@ -51,6 +54,8 @@ fn main() -> std::io::Result<()> {
5154 => "(pair (comp ?f ?j) ?g)"),
5255 // Elliott 2013
5356 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))"),
5459 // pair-precompose when ?f is id
5560 rw!("pair-factor-fst"; "(pair ?r (comp ?r ?g))" => "(comp ?r (pair id ?g))"),
5661 // pair-precompose when ?g is id
@@ -88,6 +93,10 @@ fn main() -> std::io::Result<()> {
8893 rw!("list-unroll-fold-nil"; "(comp nil (fold ?x ?f))" => "?x"),
8994 rw!("list-unroll-fold-cons"; "(comp cons (fold ?x ?f))" => "(comp (pair fst (fold ?x ?f)) ?f)"),
9095
96+ // 2 = 1 + 1
97+ rw!("bool-t-either"; "(comp t either)" => "left"),
98+ rw!("bool-f-either"; "(comp f either)" => "right"),
99+
91100 // Boolean negation
92101 rw!("bool-t-not"; "(comp t not)" => "f"),
93102 rw!("bool-f-not"; "(comp f not)" => "t"),
@@ -122,6 +131,9 @@ fn main() -> std::io::Result<()> {
122131 rw!("f-one-sign"; "(comp f-one f-sign)" => "t"),
123132 rw!("f-zero-sign"; "(comp f-zero f-sign)" => "t"),
124133 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"),
125137 ];
126138
127139 let tree = load_tree(&mut std::io::stdin())?;
--- a/test_canonical.json
+++ b/test_canonical.json
@@ -4,5 +4,6 @@
44 ["X", "(pair X X)", ["(pair id id)"]],
55 ["(pair X Y)", "(pair Y X)", ["(pair snd fst)"]],
66 ["(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)"]]
89 ]
--- a/todo.txt
+++ b/todo.txt
@@ -3,6 +3,7 @@
33 * : commands
44 * help, describe commands
55 * edit an atom's trail
6+ * save a recent REPL line as a new file
67 * More list manipulations
78 * list/eq : [X × X, 2] → [[X] × [X], 2]
89 * list/zip : [X] × [Y] → [X × Y]
@@ -33,6 +34,7 @@
3334 * Interval type?
3435 * Cantor's type of bitstrings: N -> 2
3536 * We have subobjects now, X -> 2
37+ * And finite bitstrings, [2]
3638 * Moore machines: For state type Q and input type S, Q × S -> Q
3739 * Moore transducers: [Q × S, Q] -> [Q × S, Q]
3840 * Mealy machines: For state type Q, input type S, and output type L, Q × S -> Q × L
@@ -49,5 +51,15 @@
4951 * We now can iter-maybe, short-circuiting evaluation
5052 * We need to iter-maybe but also keep track of how many steps were taken
5153 * 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)
5260 * ulimit jellification?
5361 * 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?