docs: public static <T> List<Optional<LocalProperty<T>>> match(List<LocalProperty<T>> actuals, List<LocalProperty<T>> desired)
      {
          // After normalizing actuals, each symbol should only appear once
          PeekingIterator<LocalProperty<T>> actualIterator = peekingIterator(normalizeAndPrune(actuals).iterator());
  
          Set<T> constants = new HashSet<>();
          boolean consumeMoreActuals = true;
          List<Optional<LocalProperty<T>>> result = new ArrayList<>(desired.size());
          for (LocalProperty<T> desiredProperty : desired) {
              while (consumeMoreActuals && actualIterator.hasNext() && desiredProperty.isSimplifiedBy(actualIterator.peek())) {
                  constants.addAll(actualIterator.next().getColumns());
              }
              Optional<LocalProperty<T>> simplifiedDesired = desiredProperty.withConstants(constants);
              consumeMoreActuals &= !simplifiedDesired.isPresent(); // Only continue processing actuals if all previous desired properties were fully satisfied
              result.add(simplifiedDesired);
          }
          return result;
      }