Emmy as JavaScript library (4)
(This post is part of a series, all with the same title)
(and needs lots more text to actually explain things)
<script src="https://kloimhardt.github.io/blog/js/emmy.js/build/emmy_bundle.js"></script>
<script> var loadEnv = (name) => { window[name] = emmy[name]; return name; } </script>
["div", "mul", "sub", "add", "expt", "sin", "cos"].map(loadEnv);
var _replaceMath = (txt) =>
txt.replace(/\//g,"div")
.replace(/\*/g,"mul")
.replace(/\-/g,"sub")
.replace(/\+/g,"add")
.replace(/\^/g,"expt");
var replaceMath = _replaceMath;
var insertCommas = (txt) =>
txt.replace(/(\w+)/g,'"$1",')
.replace(/\,\s+\]/g," ]");
var makeBrackets = (txt) =>
txt.trim()
.replace(/\(/g,"[ ")
.replace(/\)/g," ],")
.replace(/,$/,"");
var textToJson = (txt) =>
JSON.parse(insertCommas(replaceMath(makeBrackets(txt))));
var _jsonToJs = (j) =>
j.constructor == Array
? jsonToJs(j[0]) + "(" + j.slice(1).map(jsonToJs) + ")"
: j;
var jsonToJs = _jsonToJs;
var swapFirst = (j) =>
j.constructor == Array
&& ["div", "mul", "sub", "add", "expt"].includes(j[1])
? [j[1], j[0]].concat(j.slice(2)).map(swapFirst)
: j.constructor == Array
? j.map(swapFirst)
: j;
var _expressionToJs = (expr) =>
expr[expr.length-1] === " "
? jsonToJs(swapFirst(textToJson(expr))) + ".toString();"
: "'add blank'";
var expressionToJs = _expressionToJs; null;
<script> var oldEval = window.eval; var newEval = (txt) => txt[0] === "(" ? oldEval(expressionToJs(txt)) : oldEval(txt); window.eval = newEval; </script>
((cos (sin 0)) + (((2 / 3) - 4) * (5 ^ 2)))
As a reminder, we can also write the prefix notation
(+ (cos (sin 0)) (* (- (/ 2 3) 4) (expt 5 2)))
(3 * (cos 0))
((3 * cos) 0)
var symbol = emmy.symbol;
cos(symbol("x")).toString();
var replaceMath = (txt) =>
_replaceMath(txt).replace(/\'(\w+)/g,"symbol_$1");
var jsonToJs = (j) =>
j.constructor == String && j.substring(0, 7) == "symbol_"
? 'symbol("' + j.substring(7, j.length) + '")'
: _jsonToJs(j);
(cos 'x)
loadEnv("to_infix");
var _preAmble = (j) => ["to_infix", j];
var preAmble = _preAmble;
var _modifyJson = (j) => preAmble(swapFirst(j));
var modifyJson = _modifyJson;
var expressionToJs = (expr) => // new
expr[expr.length-1] === " "
? jsonToJs(modifyJson(textToJson(expr)))
: _expressionToJs(expr);
(cos 'x)
((3 * (sin ^ 2)) 'x)
A nice example, click for visual version in clj-tiles
loadEnv("up");
(up (* 'R (cos 'phi))
(* 'R (sin 'phi)))
var drv = emmy.D;
var f = mul(3, expt(sin, 2));
var x = symbol("x");
drv(f)(x).toString();
var replaceD = (j) =>
j.constructor == Array
? j.map(replaceD)
: j == "D" ? "drv" : j;
var modifyJson = (j) => _modifyJson(replaceD(j));
((D (3 * (sin ^ 2))) 'x)
loadEnv("simplify");
var preAmble = (j) => _preAmble(["simplify", j]);
((D (3 * (sin ^ 2))) 'x)
Of course, prefix as well
((D (* 3 (expt sin 2))) 'x)