/** Partially evaluate the right-hand side and the conditions for each rule. */
  private static Definition evaluateDefinition(TermContext termContext) {
    Definition definition = termContext.global().getDefinition();
    /* replace the unevaluated rules defining functions with their partially evaluated counterparts */
    ArrayList<Rule> partiallyEvaluatedRules = new ArrayList<>();
    /* iterate until a fixpoint is reached, because the evaluation with functions uses Term#substituteAndEvalaute */
    while (true) {
      boolean change = false;

      partiallyEvaluatedRules.clear();
      for (Rule rule :
          Iterables.concat(
              definition.functionRules().values(), definition.anywhereRules().values())) {
        Rule freshRule = rule.getFreshRule(termContext);
        Rule evaluatedRule = evaluateRule(freshRule, termContext);
        partiallyEvaluatedRules.add(evaluatedRule);

        if (!evaluatedRule.equals(freshRule)) {
          change = true;
        }
      }

      if (!change) {
        break;
      }

      definition.functionRules().clear();
      definition.anywhereRules().clear();
      definition.addRuleCollection(partiallyEvaluatedRules);
    }

    /* replace the unevaluated rules and macros with their partially evaluated counterparts */
    partiallyEvaluatedRules.clear();
    Iterable<Rule> rules =
        Iterables.concat(
            definition.rules(),
            definition.macros(),
            definition.patternRules().values(),
            definition.patternFoldingRules());
    for (Rule rule : rules) {
      partiallyEvaluatedRules.add(evaluateRule(rule, termContext));
    }
    definition.rules().clear();
    definition.macros().clear();
    definition.patternRules().clear();
    definition.patternFoldingRules().clear();
    definition.addRuleCollection(partiallyEvaluatedRules);

    return definition;
  }