code: private ExpressionAndSubstitution convertIntoExpressionAndSubstitution(ImmutableExpression expression,
                                                                                              ImmutableSet<Variable> nonLiftableVariables)
              throws UnsatisfiableConditionException {
  
          ImmutableSet<ImmutableExpression> expressions = expression.flattenAND();
          ImmutableSet<ImmutableExpression> functionFreeEqualities = expressions.stream()
                  .filter(e -> e.getFunctionSymbol().equals(EQ))
                  .filter(e -> {
                      ImmutableList<? extends ImmutableTerm> arguments = e.getTerms();
                      return arguments.stream().allMatch(t -> t instanceof NonFunctionalTerm);
                  })
                  .collect(ImmutableCollectors.toSet());
  
          ImmutableSubstitution<NonFunctionalTerm> normalizedUnifier = unify(functionFreeEqualities.stream()
                          .map(ImmutableFunctionalTerm::getTerms)
                          .map(args -> Maps.immutableEntry(
                                  (NonFunctionalTerm) args.get(0),
                                  (NonFunctionalTerm)args.get(1))),
                  nonLiftableVariables);
  
          Optional<ImmutableExpression> newExpression = immutabilityTools.foldBooleanExpressions(
                  Stream.concat(
                          // Expressions that are not function-free equalities
                          expressions.stream()
                                  .filter(e -> !functionFreeEqualities.contains(e))
                                  .map(normalizedUnifier::applyToBooleanExpression),
  
                          // Equalities that must remain
                          normalizedUnifier.getImmutableMap().entrySet().stream()
                                  .filter(e -> nonLiftableVariables.contains(e.getKey()))
                                  .map(e -> termFactory.getImmutableExpression(EQ, e.getKey(), e.getValue()))
                  ));
  
          return new ExpressionAndSubstitution(newExpression,
                  normalizedUnifier.reduceDomainToIntersectionWith(
                          Sets.difference(normalizedUnifier.getDomain(), nonLiftableVariables).immutableCopy()));
      }
docs: TODO: explain
  
  Functional terms remain in the expression (never going into the substitution)