public <A> Cfg<A>
	map(final Function<? super Terminal<? extends T>, ? extends A> mapper) {
		requireNonNull(mapper);

		final var cache = new HashMap<Terminal<T>, Terminal<A>>();
		final Function<Terminal<T>, Terminal<A>> mapping = t -> cache
			.computeIfAbsent(t, t2 -> new Terminal<>(t2.name(), mapper.apply(t2)));

		@SuppressWarnings("unchecked")
		final List<Rule<A>> rules = rules().stream()
			.map(rule -> new Rule<>(
				(NonTerminal<A>)rule.start(),
				rule.alternatives().stream()
					.map(expr -> new Expression<>(
						expr.symbols().stream()
							.map(sym ->
								sym instanceof Cfg.Terminal<T> t
									? mapping.apply(t) : (Symbol<A>)sym
							)
							.toList()
						))
					.toList()
				))
			.toList();

		return Cfg.of(rules);
	}
Maps the values of the terminal symbols from type {@code T} to type
{@code A}.

@param mapper the mapper function
@param <A> the new value type of the terminal symbols
@return the mapped grammar
@throws NullPointerException if the given mapper is {@code null}
jenetics.ext/src/main/java/io/jenetics/ext/grammar/Cfg.java