JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

JavaScript

function evaluate([type, ...args]) {
	switch (type) {
  	case "int":
    	return args[0];
    case "add":
    	return args.map(evaluate).reduce((a, b) => a + b, 0);
    case "multiply":
    	return args.map(evaluate).reduce((a, b) => a * b, 1);
  }
}

function isExpr(expr) {
	return Array.isArray(expr) && expr.length > 1 && typeof expr[0] === "string";
}

function isInt(value) {
  return (expr) => {
  	if (!isExpr(expr)) return false;

    const [type, ...args] = expr;
    return type === "int" && args[0] === value;
  }
}

function simplify([type, ...args]) {
  args = args.map(arg => isExpr(arg) ? simplify(arg) : arg);

	switch (type) {
  	case "add": {
    	if (!args.some(([type]) => type !== "int")) {
      	return simplify(["int", args.reduce((value, [type, ...args]) => value + args[0], 0)]);
      }
    	break;
    }
    case "multiply": {
    	if (args.length === 1) {
      	return simplify(args[0]);
      }
    	if (!args.some(([type]) => type !== "int")) {
      	return simplify(["int", args.reduce((value, [type, ...args]) => value * args[0], 1)]);
      }
      if (args.some(isInt(0))) {
      	return simplify(["int", 0]);
      }
      if (args.some(isInt(1))) {
      	return simplify(["multiply", ...args.filter(arg => !isInt(1)(arg))]);
      }
      break;
    }
  }
  
  return [type, ...args];
}

function derivative(respecting = "x") {
	const d = ([type, ...args]) => {
    switch (type) {
      case "int":
        return ["int", 0];
      case "add":
        return ["add", ...args.map(d)];
      case "multiply": {
      	let terms = [];
      	for (let i = 0; i < args.length; i++) {
        	let innerTerms = [];
          for (let j = 0; j < args.length; j++) {
            if (j === i) {
            	innerTerms.push(d(args[j]));
            } else {
            	innerTerms.push(args[j]);
            }
          }
          terms.push(["multiply", ...innerTerms]);
        }
        return ["add", ...terms];
      }	
      case "variable":
      	if...