Post B86vPNMHqMqt8ST9oe by icedquinn@blob.cat
(DIR) More posts by icedquinn@blob.cat
(DIR) Post #B86p48cwosPpdnkhM0 by icedquinn@blob.cat
0 likes, 0 repeats
the tcl spec is pretty funny.how to implement tcl: get fucked, sob profusely.
(DIR) Post #B86tMGTYmEux0oGBUm by pry@raru.re
0 likes, 0 repeats
@icedquinn I feel like I know a bunch of folks who like tcl
(DIR) Post #B86u9X2ZyhYyZo8H56 by icedquinn@blob.cat
0 likes, 0 repeats
@pry its good at the one little thing it does
(DIR) Post #B86uoBb6bkWLwdfQlE by pry@raru.re
0 likes, 0 repeats
@icedquinn Yeah thats fair. At this point I just use python... which isn't great but it is what I know
(DIR) Post #B86uxkkVHhO9ZVcoEq by icedquinn@blob.cat
0 likes, 0 repeats
@pry python didn't exist yet (or was like python 1 and super early.) tcl was mostly a macro language.it's still actually good at that. it's just not good at wrangling objects (there are several object oriented modules for it but they end up with goofy memory management problems afaik)
(DIR) Post #B86vAi2KgFmKvL8t0q by pry@raru.re
0 likes, 0 repeats
@icedquinn how do you know so much about so many languages? I've been getting very interested in language design and its been a really fun rabbit hole to go down, but still havent read up a ton of older stuff
(DIR) Post #B86vPNMHqMqt8ST9oe by icedquinn@blob.cat
0 likes, 0 repeats
@pry adhd and poor use of my life :blobcatnomouth:
(DIR) Post #B86vVabrUN4RyFiX2m by pry@raru.re
0 likes, 0 repeats
@icedquinn my interests are definitely too scattered rn so i kinda get thatat the very least it feels like a big problem i have is not making durable progress towards learning anything in particular
(DIR) Post #B86wv1D9p1NBfSqqf2 by icedquinn@blob.cat
0 likes, 0 repeats
@pry my current dream language is something like Terra/Lua but with a Jupyter notebook interface.so you would write down the start/mid/finish steps of a hash or crypt function, or just the pixel transfer function for paint progs, and it would be this really neat and clean little bit of something like Io.the notebook is there for throwing tools at the code and being shown what it did. its like a mixture of tactics (from the prover languages) and compiler explorers.a lot of work is wasted because the code doesn't represent what it means and especially c/c++ code gets confounded a lot with changes made hoping the compiler does something, not because it actually expresses the intent.nile/gezira showed that the actual intent of an entire graphics canvas library is like 800 SLOC, and the rest is just tax.
(DIR) Post #B86yRYnIb3mp2npyCm by pry@raru.re
0 likes, 0 repeats
@icedquinn I've used languages like Lean where the notebook explorer sort thing is really cool.> so you would write down the start/mid/finish steps of a hash or crypt function, or just the pixel transfer function for paint progs, and it would be this really neat and clean little bit of something like Io.I don't understand this part.I should look at nile/gezira, have not heard of it before
(DIR) Post #B86yroha4gXduVgOJc by icedquinn@blob.cat
0 likes, 0 repeats
@pry in some code like xxhash there are separate "streaming" and "one-shot" functions. streams have a start, end, and feeding them bytes between. one-shots are functionally all 3 in one call.in the c/c++ code they duplicate the implementation because the one-shot has less overhead for small keys (like hash tables.)this is an optimization artifact; the one-shot should just be the three steps with a note to inline them together and continue. in this case, you'd do that, and then the journal at the bottom would specifically say "now inline those as though i wrote it that way" and it should show you what the function now is.people shouldn't be making unreadable code and tabbing between the compiler inspector and back. they should be writing inordinantly clear code and telling the filters how to get it right
(DIR) Post #B86zHOafmLOCSMeGjw by pry@raru.re
0 likes, 0 repeats
@icedquinn so better compiler hints? or I suppose not really hints. more like forcibly inline. That should be possible with c preprocessor fuckery (ugly), or rust macros
(DIR) Post #B86zIKRofQldtgx0zI by icedquinn@blob.cat
0 likes, 0 repeats
@pry nile/gezira was basically just a one-off language for a project. it treated the whole process like little tiny stream processing kernels and they worked on typed streams. so there was a single "i take in these beziers and i give out straight lines." the kernel would then split beziers and either re-queue them to itself or send a line out the side.the compiler re-added all the boilerplate. in graphics code (esp. old graphics) stuff like 8-bit, 16-bit, and 32-bit color, is just the same algorithm but it has to be copied over and over and re-optimized because 32-bit color uses floats where you have the standard [0, 1] number domain, but 8-bit color is 0-255 so you end up having to do bullshit (either converting to float to do the math and then back to 8-bit, or working out the math in 8-bit)thus a lot of what cairo and skia do is basically just many lines of taxation on top of what little they actually have to do
(DIR) Post #B871iOW6MQT9xGVoO0 by icedquinn@blob.cat
0 likes, 0 repeats
@pry no, it's not compiler hints.the compiler *is* the journal. you run tactics/passes on the model and get incrementally closer to a shippable artifact. if its not important code then its like farming the proof out to sledgehammer or simp.if you have specific needs then you ask for the pipeline you want. its more like how sympy lets you enter a math expression and iteratively substitute variables out of it. it's more about having reusable instruments (like the nanopass framework, and e-graphs) where you can specifically go "for this one trick, i really do need you to inline x, y, and z" and then it shows you if that did what you expected.its basically making the steps people take to optimize HPC code explicit, auditable, learnable, and replacable, and along the way you get some neat stuff (like being able to specifically guide it to vectorizing some math function instead of praying.)
(DIR) Post #B8F5y67C4mKRpBqe80 by pry@raru.re
0 likes, 0 repeats
@icedquinn oh I see, that makes sense. I've seen DSLs for things like this. Like for network packet analysis and the like.
(DIR) Post #B8F62kHQgXdnYKqt4C by pry@raru.re
0 likes, 0 repeats
@icedquinn This is a really really cool idea. Does it have a name? (Also big fan of e-graphs tho haven't really had an excuse to do much with them yet)
(DIR) Post #B8F6L5nJQzjJUTVu7M by icedquinn@blob.cat
0 likes, 0 repeats
@pry i've never seen anyone do it. i just played around with sympy and terra/lua a few times and thought this is probably how we should be doing high performance code.haven't written any e-graph or query stuff yet. query engines look like they suck, although maybe e-graphs make query optimizers suck less too.have to get around to actually implementing the io clone though :blobcatnomouth:
(DIR) Post #B8F6oCMS69kAFrpRLc by pry@raru.re
1 likes, 0 repeats
@icedquinn I saw a really great article about using deforestation and continuation pass style for query vectorization for databases.https://remy.wang/blog/cps.htmlI honestly just need to get off my ass and implement literally anything. I love programming languages and I think I should just implement a basic interpreter and go from there. (I'm especially interested in language design)
(DIR) Post #B8FBQ3QUAMfNMf1Phg by icedquinn@blob.cat
0 likes, 0 repeats
@pry i don't know much about the deforestation tactic. i did ask a model about it and claude didn't think it was a big win.e-graphs seem like they could make query optimizing straightforward but apparently they can use a lot of memory. idk.
(DIR) Post #B8TI6WN8N1VFHUh59M by ink@social.xenofem.me
0 likes, 0 repeats
@pry @icedquinn https://dl.acm.org/doi/10.5555/373953.373961
(DIR) Post #B8TI6WgdCX6CFxoeXY by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry i spent chunks of yesterday considering if a small prolog would be helpful in my metamodel toolkit. it still sort of came up a large bag of "it depends."datalog isn't *too* bad as a querying languge. optimizing it can be pants, but has been done. basically through magic sets (which is adjacent to deforesting; it tries to project binding restrictions downward), though everything else about optimizing queries starts getting in to a space where i'd rather just throw it at e-graphs.prolog's shit is extremely poorly documented (there's something called a WAM that nobody ever fully specifies), bodgy (there's special versions of the runtime dedicated to cramming on constraint optimizations), and seems to be mostly focused on generative queries over selective ones, and then mercury which takes prolog and adds hard typing to whether heads can return zero, one, or many facts, so. :blobcatdizzy2: game engine only really needed an expression parser. kinda do want to get back to shipping at some point.
(DIR) Post #B8hOrLCJEFBDMeXRGy by ink@social.xenofem.me
0 likes, 0 repeats
@icedquinn @pry prolog is well doc't? I've been paid to write it
(DIR) Post #B8hOrLSyEIVWCKKkF6 by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry some of the docs on the warran abstract machine notoriously note that the report is extremely terse and leaves some things unspecified. then features like modules and imports are left to dialects.its basically an idea of a language that gets crumpled up for actual field use (back when it was used) https://iceworks.cc/blog/pidl/ similar to how datalog has been coming back in a similar way (dialected, because the spec itself barely says anything)
(DIR) Post #B8hPPyFkWmdqL3f0DI by ink@social.xenofem.me
0 likes, 0 repeats
@icedquinn @pry I like clojure.logic as the equiv? It's silly to get stuck in query semantics
(DIR) Post #B8hPPyYBQFO3GEHiwi by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry :blobcatshrug2: i've never done the query engine part. parsers were always on the struggle bus.at the end of the day all i learned is table scan is what you end up doing anyway and the whole rest of the field is just trying to get out of table scanning as long as possible.
(DIR) Post #B8hQ31ZI8TmzukQIIC by ink@social.xenofem.me
0 likes, 0 repeats
(defun subst-cons-lambda (new-lambda old-lambda cell) (if (and cell (listp cell)) (if (funcall old-lambda cell) (funcall new-lambda cell) (cons (if (listp (car cell)) (subst-cons-lambda new-lambda old-lambda (car cell)) (if (funcall old-lambda (car cell))(funcall new-lambda (car cell))(car cell)))(subst-cons-lambda new-lambda old-lambda (cdr cell))))))(defun replace-symbol-cell (cell old new) (subst-cons-lambda (lambda (x) new) (lambda (x) (eq x old)) cell))(defun substitute-predicate (cell predicate replacement) (subst-cons-lambda (lambda (x) replacement) (lambda (x) (and (consp x) (equal (first x) predicate))) cell));;;;;;;;;;;;;;;;;;(defparameter connectives '(∧ ∨ →))(defparameter quantifiers '(∀ ∃))(defparameter operators '(¬))(defparameter logical-symbols `(,@connectives ,@quantifiers ,@operators))(defparameter non-logical-symbols '(x y z x0 y0 z0 x1 y1 z1 x_ y_ z_))(defparameter variable-symbols '(a b c d e f g h i j k l m))(defun variable? (term) (member term variable-symbols))(defun constant? (term) (not (variable? term)))(defun implication-subformulas? (formula) "if FORMULA is an Implication, return the condition and consequence" (case (first formula) ('→ (let ((condition (second formula)) (consequence (third formula))) `(,condition ,consequence)))))(defun universal-quantified? (formula) "if FORMULA is Universally Quantified at its root, return the Quantified Domain and the stated Property " (case (first formula) ('∀ (let ((domain (second formula)) (property (third formula))) `(,domain ,property))))) (defun convert-to-cnf (formula) "convert a quantified First Order Logic clause to Conjunctive Normal Form" (case (first formula) ('∀ (let ((domain (second formula)) (property (third formula))) (case (first property) ('→ (let ((condition (second property)) (consequence (third property))) `(∨ (¬ ,condition) ,consequence) ))) )) ('∃ 'make-skolem-functions) (otherwise formula) ;; Additional Steps ;; https://en.wikipedia.org/wiki/Conjunctive_normal_form#Converting_from_first-order_logic ;; ^ (convert-to-negation-normal-form) ;; (de-morgans-law) ;; (Skolemize) ))(defun predicate-functionp (literal) "any (P X ...)" (if (negative-literalp literal) (setq literal (second literal))) (if (and (listp literal) (symbolp (first literal)) (rest literal) (not (member (first literal) logical-symbols)) ) (first literal) nil))(defun predicate-args (literal) "(P x y z) -> (x y z)" (if (negative-literalp literal) (setq literal (second literal))) (rest literal))(defun negation (literal) "P -> ¬P" (if (and (consp literal) (negative-literalp literal)) (second literal) `(¬ ,literal)))(defun literalp (formula) "(¬ (P X)) or (P X)" (and (listp formula) (or (and (eq (first formula) '¬) (predicate-functionp (second formula))) (predicate-functionp formula))))(defun negative-literalp (literal) "(¬ (P X))" (and (consp literal) (eq (first literal) '¬)))(defun clausep (formula) "any (∨ literal1 literal2...)" (and (listp formula) (eq (first formula) '∨))) (defun clause-literals (clause) "return positive and negative literals of CLAUSE" (if (literalp clause) (list clause) (loop for i in clause if (literalp i) collect i if (clausep i) append (clause-literals i))))(defun predicate-pattern (literal) "(P foo bar foo...) -> (P a b a...)" (setq argument-pattern (loop :for i :upto (1- (length (predicate-args literal))) :collect (nth i variable-symbols))) (if (negative-literalp literal) `(¬ (,(predicate-functionp literal) ,@argument-pattern)) `(,(predicate-functionp literal) ,@argument-pattern)))(defun two-matching-clauses? (a b) "Find the same predicate in two CLAUSEs A and B where it is negated in one but not the other" (setq literals-a (clause-literals a)literals-b (clause-literals b)positive-a '() negated-a '()positive-b '() negated-b '()positive-in-a-negated-in-b '()negated-in-a-positive-in-b '()) (loop for literal in literals-a do (if (negative-literalp literal) (push (list (predicate-pattern literal) literal) negated-a) (push (list (predicate-pattern literal) literal) positive-a))) (loop for literal in literals-b do (if (negative-literalp literal) (push (list (predicate-pattern literal) literal) negated-b) (push (list (predicate-pattern literal) literal) positive-b))) (loop for positive-literal in positive-a do (if (assoc (negation (first positive-literal)) negated-b :test #'equal) (push positive-literal positive-in-a-negated-in-b))) (loop for positive-literal in positive-b do (if (assoc (negation (first positive-literal)) negated-a :test #'equal) (push positive-literal negated-in-a-positive-in-b))) (list positive-in-a-negated-in-bnegated-in-a-positive-in-b) ) (defun equation? (formula) "if FORMULA is an Equation of the form (= A B), return (A B)" (if (and (listp formula) (eq (first formula) '=)) (list (second formula) (third formula))))(defun equality-predicate-match? (equation) "if EQUATION matches F(t_1...t_i) = F(t'_1...t'_i) return (t_1...) = (t'_1...)" (destructuring-bind (left right) (equation? equation) (if (and (predicate-functionp left) (predicate-functionp right) (equal (predicate-pattern left) (predicate-pattern right)))(list (predicate-args left) (predicate-args right)))))(defun unification (equations substitutions step &optional debug) "find the SUBSTITUTIONS of the Most General Unifier if it exists for EQUATIONS" (loop for equation in equations do (if debug (print `(:EQUATIONS ,equations :SUBSTITUTIONS ,substitutions))) ;; Look for equation matching form F(t_1...t_i) = F(t'_1...t'_i) (let ((matched-predicate-args (equality-predicate-match? equation))) (if matched-predicate-args (destructuring-bind (left-args right-args) matched-predicate-args ;; remove the F(t...) = F(t'...) equation (setq equations (remove equation equations :test #'equal)) ;; and add a new derived t... = t'... equations (loop :for i :upto (1- (length left-args)) do (push `(= ,(nth i left-args) ,(nth i right-args)) equations)) ) (progn ;; Remove redundant equations of form 'x = x' (if (equal (second equation) (third equation)) (setq equations (remove equation equations :test #'equal)) (progn ;; Check if equation is of form x = t where x is a variable and t a constant? (let ((term-variable (equality-term-variable-match? equation))) (if term-variable (destructuring-bind (left right) term-variable ;; Occurs Check : ;; if t is a term in which x occurs, the algorithm halts with no output unifier ;; Substitution ;; If x does not occur in t, then let [x/t] denote the substitution that maps x to t and set EQUATIONS to be the set of equations such that for each EQUATION is EQUATION[x/t] (replace all instances of x with t) and add to SUBSTITUTIONS '(X T) (setq left_ left right_ right) (setq equations (mapcar (lambda (e) (replace-symbol-cell e left right)) equations)) (push (list left right) substitutions) ;; (break) ))) )))))) ;; if Equations are exhausted, return the substitute or nil (the identity operator) (if equations (unification equations substitutions (1+ step) debug) (list equations substitutions :steps step)) )(defun equality-term-variable-match? (equation) "if EQUATION is of form X = T where X is a Variable and T is a Constant Term, return (X T)" (destructuring-bind (left right) (equation? equation) (if (and (variable? left) (constant? right))`(,left ,right)))) (defun resolution (premises) "perform resolution procedure on PREMISES to derive provable Conclusions" (let* ((conj-normal-forms (loop :for formula :in premises :collect (convert-to-cnf formula))) ) (destructuring-bind (negated-in-b negated-in-a) (two-matching-clauses? (first conj-normal-forms) (second conj-normal-forms)) (let* ((predicate-negated (second (first negated-in-a))) (predicate-pattern (first (first negated-in-a))))(setq unification (unification `((= ,predicate-pattern ,predicate-negated)) '() 0 'debug) most-general-unifier (first (second unification)))(print `(MOST GENERAL UNIFIER FOUND TO BE ,most-general-unifier))(destructuring-bind (to-substitute substitution) most-general-unifier (setq to-subs to-substitutesub substitutionsolved-premise(subst-cons-lambda (lambda (x) nil) (lambda (x) (and (consp x) (eq (predicate-functionp x) (predicate-functionp (predicate-pattern predicate-pattern))))) (rest (first conj-normal-forms)))) (second (subst-cons-lambda (lambda (y) substitution) (lambda (y) (eq y to-substitute)) solved-premise)) )))));;(defparameter test-premises '((∀ a (→ (Greek a) (European a)))(Greek Homer)))(defun tests () (resolution test-premises) (unification '((= (F a) (F homer))) '() 0) (convert-to-cnf '(∀ a (→ (Greek a) (European a)))) )
(DIR) Post #B8hQ31zAaGUPD0Wxd2 by icedquinn@blob.cat
0 likes, 0 repeats
@ink :blobcatgoogly: i'm not a lisp interpreter
(DIR) Post #B8hSIsJqUWaflostYO by icedquinn@blob.cat
0 likes, 0 repeats
@ink most of that work recently is because i needed a parser for expressions in some narrative storytelling stuff.this somehow lead to rereading on some logic programming and query sauce.i've basically settled now, though, from a gamedev perspective i don't actually need much more than stratified datalog and some calculator syntax. :comfyheart:
(DIR) Post #B8hSStAmAjK5JWPv8K by icedquinn@blob.cat
0 likes, 0 repeats
@ink some of it comes down to just needed enough logic bits to make meta-modelling a TTRPG ruleset suck less. because those are full of exceptions, and for a for a few steps there were special cases, and then refactoring that down to where now its just like<affect name="drunk"><when cond="event('rolled-dice'), die-face(1)"> ...</when></affect>(yeah its xml, the kdl parsers not done)
(DIR) Post #B8hUQjYNAKeWoDYQfg by ink@social.xenofem.me
0 likes, 0 repeats
@icedquinn oh you want predicate state transition assigns
(DIR) Post #B8hUQjrA2TgJkULQxM by icedquinn@blob.cat
0 likes, 0 repeats
@ink yep. the upstream use is just declarative predicates.for storynexus stuff its just a check of "is this card valid to draw" against game state, for crpg its usually "is that move valid for this target," and there's a long history of basically re-creating the same mechanics informally (larian, black isle, early bioware)the prolog aspect was mostly out of curiosity. accidentally found picat through that--and might use it for the planner functions personally--but i'm not sure it would make it in to either the runtime or codegen parts.some of the prolog/picat semantics might sneak in to the codegen part though i haven't worked out if that'd be useful yet. "here's some rules, generate cases, then feed those to the output template to write code files" would be all that part does.
(DIR) Post #B8hmb7FZiMwgNFrW2S by ink@social.xenofem.me
0 likes, 0 repeats
@icedquinn why not just use gurps lol
(DIR) Post #B8hmb7aUSbfxQ7eDdg by icedquinn@blob.cat
0 likes, 0 repeats
@ink how would that help it still has arbitrary complexity as a rulesetunless you mean the base resolution rules.
(DIR) Post #B8hmr6Hz3Whu1hbvsW by ink@social.xenofem.me
0 likes, 0 repeats
@icedquinn how do you plan on testing the imba on your work?
(DIR) Post #B8hmr6ZM0wbMtZjnxA by icedquinn@blob.cat
0 likes, 0 repeats
@ink imba?
(DIR) Post #B8hxDpbIGijQTC7Wu8 by pry@raru.re
0 likes, 0 repeats
@icedquinn @ink honestly ive never been that interested in parsers. learned about earley parsing and a couple other algorithms but I'm much else interested in that than like everything that comes after I have an AST
(DIR) Post #B8hxoGRTwu8q8vu5js by ink@social.xenofem.me
0 likes, 0 repeats
@pry @icedquinn i have written a lot of how coupled syntax and semantic production are bound
(DIR) Post #B8hxoGiquK2J0o1xoW by pry@raru.re
0 likes, 0 repeats
@ink @icedquinn oh? have any links, sounds interesting
(DIR) Post #B8hxpXucTvOCcB8yci by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry earley and tomita are basically fine.i have zimmerman's paper on XGLR and its more annoying to read than it needs to be (academia) but goes in to a bit of detail about it. i ended up not using that method and paper for [name not public yet] and went with pegs, but tree-sitter is based on tomita, so.
(DIR) Post #B8hy6hxaNRyKhUiMy0 by ink@social.xenofem.me
0 likes, 0 repeats
@pry @icedquinn https://github.com/drea8/cl-refal/blob/master/src/interpret.lispi had a few articles on my old site on this theme:https://www.youtube.com/watch?v=3b1YRqDQ25w
(DIR) Post #B8hy6iCTU5sjRfgGAq by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry i wish this was typeset :blobcatgooglycry:
(DIR) Post #B8hyiu6JgbypMJ0mKu by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry it wasn't until pegs that i begun to understand what the fuck was going on. this is mostly a failure in literature. parsing ends up blithering about knuth's table algorithms and making everything sound worse than it really is.pegs -> basically just short-hand for recursive descent. it maps trivially to basically any structured programming 1:1. the parsing people crow that backtracking is death, but most industrial compilers ship RD parsers, so pegs have been rather unfairly eating shit considering they're the dominant pattern in disguise. and RD is basically just "write serial recursive functions to read the thing one at a time."NFAs are one of those things that everyone tries to make sound horrible and cryptic but its the simplest shit in the fucking universe. just walk around a graph and consume input. :neocat_facepalm: afaik the biggest thing about earley -> tomita is earley is always speculatively parsing every production as a separate cursor for each valid outcome and closes the cursors when they can't possibly match. tomita/zimmerman merge the rules so they only fork when the rules actually call for it. this is basically the same as thompson nfas and ross cox has some nice articles on how those are actually really basic once you strip the encryption away and the VM basically works entirely the same (thompson regex are actually forking constantly, which is supposedly what makes tomita awful, but it turns out its actually not important at all because the states merge well :blobcatgoogly:)may or may not attempt to do articles on it. i feel like these concepts are actually much simpler than everyone lets on. somehow comp sci has just been completely assinine in explaining them
(DIR) Post #B8hyxQnKvb9koM3qLI by ink@social.xenofem.me
0 likes, 0 repeats
@icedquinn @pry the mass availability of parsing tooling for really bad languages like C++ like yacc or whatever ruined the notion of state production models
(DIR) Post #B8hyxR6TmQT7lj18BE by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry yacc and bison are also just terrible, to be fair.
(DIR) Post #B8i2iNAkVt4H385St6 by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry > Refal is based on pattern matching. Its pattern matching works in conjunction with term rewriting.:comfyeyes: that's eerily similar to what my thing is for.
(DIR) Post #B8iFYg0suJYrzYBDQO by icedquinn@blob.cat
0 likes, 0 repeats
@ink @pry wild. claude was like "have you considered not doing that" and listed TXL. digging in the txl repos has the thing they built that on top of https://github.com/CordyJ/Open-TuringPlus/blob/main/doc/SSL_Introduction.pdf:blobcatdizzy: neat.term rewrite stack could be pretty useful. was also mewing about how one could finagle the interpreter around a little to get refal rules to produce an e-graph instead (instrumenting the top level rewrites to cut around what it eats and produce e-classes.)the robot was upset like "quinn term rewriting languages are shit" except for.. this specific kind of problem, hm.