A categorical programming language
リビジョン | caae86fc44c3d23102b8225e63fc6266edaf3fbd (tree) |
---|---|
日時 | 2022-09-19 02:41:02 |
作者 | Corbin <cds@corb...> |
コミッター | Corbin |
Honey can evaluate nat/256 in the browser!
@@ -3,3 +3,4 @@ use nix | ||
3 | 3 | eval $(keychain --eval --agents ssh) |
4 | 4 | |
5 | 5 | # export CAMMY_HIVE="$(pwd)/hive/" |
6 | +export HONEY_HIVE="$(pwd)/hive.json" |
@@ -26,9 +26,122 @@ def home(): | ||
26 | 26 | <h2>Hive Stats</h2> |
27 | 27 | <p>There are {dipperCount} dippers available.</p> |
28 | 28 | <p>The heap has {heapCount} rows.</p> |
29 | + <form id="dipper-form"> | |
30 | + <input type="textbox" id="dipper" /> | |
31 | + <button id="go" type="submit">Go!</button> | |
32 | + </form> | |
33 | + <div id="log"> | |
34 | + <p>Log starts here</p> | |
35 | + </div> | |
36 | + <script type="text/javascript"> | |
37 | + function log(s) {{ | |
38 | + document.getElementById("log").innerHTML += s; | |
39 | + }} | |
40 | + function fetchJSON(url) {{ | |
41 | + return fetch(url).then((resp) => resp.json()); | |
42 | + }} | |
43 | + function extract(expr) {{ | |
44 | + if (typeof expr === "string") {{ | |
45 | + return new Promise((resolve, reject) => resolve(expr)); | |
46 | + }} else if (typeof expr === "number") {{ | |
47 | + const url = "/extract/" + expr; | |
48 | + return fetchJSON(url).then(extract); | |
49 | + }} else if (Array.isArray(expr)) {{ | |
50 | + return Promise.all(expr.map(extract)); | |
51 | + }} else {{ | |
52 | + console.log("Can't extract from", expr); | |
53 | + }} | |
54 | + }} | |
55 | + const prims = {{ | |
56 | + "id": x => x, | |
57 | + "ignore": _ => null, | |
58 | + "fst": ([x, y]) => x, | |
59 | + "snd": ([x, y]) => y, | |
60 | + "zero": _ => 0, | |
61 | + "succ": n => n + 1, | |
62 | + }}; | |
63 | + function compile(expr) {{ | |
64 | + console.log("compile", expr); | |
65 | + if (Array.isArray(expr)) {{ | |
66 | + const l = expr.slice(1).map(compile); | |
67 | + switch (expr[0]) {{ | |
68 | + case "comp": {{ | |
69 | + const [f, g] = l; | |
70 | + return x => g(f(x)); | |
71 | + }} | |
72 | + case "pair": {{ | |
73 | + const [f, g] = l; | |
74 | + return x => [f(x), g(x)]; | |
75 | + }} | |
76 | + case "curry": {{ | |
77 | + const [f] = l; | |
78 | + return x => y => f([x, y]); | |
79 | + }} | |
80 | + case "uncurry": {{ | |
81 | + const [f] = l; | |
82 | + return ([x, y]) => f(x)(y); | |
83 | + }} | |
84 | + case "pr": {{ | |
85 | + const [z, s] = l; | |
86 | + return x => {{ | |
87 | + var rv = z(null); | |
88 | + while (x !== 0) {{ | |
89 | + x -= 1; | |
90 | + rv = s(rv); | |
91 | + }} | |
92 | + return rv; | |
93 | + }} | |
94 | + }} | |
95 | + default: | |
96 | + throw new TypeError("unknown constructor " + | |
97 | + expr[0]); | |
98 | + }} | |
99 | + }} else {{ | |
100 | + return prims[expr]; | |
101 | + }} | |
102 | + }} | |
103 | + const textbox = document.getElementById("dipper"); | |
104 | + document.getElementById("dipper-form").addEventListener("submit", (e) => {{ | |
105 | + const url = "/dip/" + textbox.value; | |
106 | + log("<p>Got a click! Will fetch URL " + url + "</p>"); | |
107 | + fetchJSON(url).then(({{expr, trail}}) => {{ | |
108 | + log("<p>Token is " + expr + "</p>"); | |
109 | + log("<p>Trail is " + trail + "</p>"); | |
110 | + const extracted = extract(expr); | |
111 | + extracted.then((ex) => {{ | |
112 | + log("<p>Finished extraction, got " + ex + "</p>"); | |
113 | + const compiled = compile(ex); | |
114 | + log("<p>Result: " + compiled(null) + "</p>"); | |
115 | + }}); | |
116 | + }}); | |
117 | + e.preventDefault(); | |
118 | + }}, false); | |
119 | + </script> | |
29 | 120 | </body> |
30 | 121 | """ |
31 | 122 | |
123 | +def substitute(context, expr): | |
124 | + if isinstance(expr, list): | |
125 | + return [expr[0]] + [substitute(context, sub) for sub in expr[1:]] | |
126 | + elif isinstance(expr, int): | |
127 | + return substitute(context, heap[expr]) | |
128 | + elif isinstance(expr, str) and expr.startswith("@"): | |
129 | + return context[int(expr[1:])] | |
130 | + return expr | |
131 | + | |
132 | +FUNCTORS = "comp", "pair", "curry", "uncurry", "pr" | |
133 | + | |
134 | +def maybeApplyFunctor(expr): | |
135 | + if isinstance(expr, list) and expr[0] not in FUNCTORS: | |
136 | + context = expr[1:] | |
137 | + target = heap[symbols[expr[0]][0]] | |
138 | + return substitute(context, target) | |
139 | + return expr | |
140 | + | |
141 | +@app.route("/extract/<int:token>") | |
142 | +def extract(token): | |
143 | + return jsonify(maybeApplyFunctor(heap[token])) | |
144 | + | |
32 | 145 | @app.route("/dippers") |
33 | 146 | def dippers(): |
34 | 147 | return jsonify({name: url_for("dip", name=name) for name in symbols}) |
@@ -62,7 +175,7 @@ class Dip(MethodView): | ||
62 | 175 | if name not in symbols: |
63 | 176 | abort(404) |
64 | 177 | index, trail = symbols[name] |
65 | - return jsonify({"expr": resolve(index), "trail": trail}) | |
178 | + return jsonify({"expr": index, "trail": trail}) | |
66 | 179 | |
67 | 180 | def put(self, name): |
68 | 181 | d = request.get_json() |
@@ -44,6 +44,6 @@ in pkgs.stdenv.mkDerivation { | ||
44 | 44 | # experimenting with hive management |
45 | 45 | ranger |
46 | 46 | # ??? |
47 | - openapi-generator-cli yaml2json | |
47 | + openapi-generator-cli yaml2json python3Packages.virtualenv | |
48 | 48 | ]; |
49 | 49 | } |
@@ -0,0 +1,4 @@ | ||
1 | +#!/bin/sh | |
2 | + | |
3 | +yaml2json <honey.yaml >honey.json | |
4 | +openapi-generator-cli generate -i honey.json -o honey-flask/ -g python-flask |