code: def substitute(expression: Union[Expression, Pattern], substitution: Substitution) -> Replacement:
      
      if isinstance(expression, Pattern):
          expression = expression.expression
      return _substitute(expression, substitution)[0]
docs: Replaces variables in the given *expression* using the given *substitution*.
  
      >>> print(substitute(f(x_), {'x': a}))
      f(a)
  
      If nothing was substituted, the original expression is returned:
  
      >>> expression = f(x_)
      >>> result = substitute(expression, {'y': a})
      >>> print(result)
      f(x_)
      >>> expression is result
      True
  
      Note that this function returns a list of expressions iff the expression is a variable and its substitution
      is a list of expressions. In other cases were a substitution is a list of expressions, the expressions will
      be integrated as operands in the surrounding operation:
  
      >>> print(substitute(f(x_, c), {'x': [a, b]}))
      f(a, b, c)
  
      If you substitute with a `Multiset` of values, they will be sorted:
  
      >>> replacement = Multiset([b, a, b])
      >>> print(substitute(f(x_, c), {'x': replacement}))
      f(a, b, b, c)
  
      Parameters:
          expression:
              An expression in which variables are substituted.
          substitution:
              A substitution dictionary. The key is the name of the variable,
              the value either an expression or a list of expression to use as a replacement for
              the variable.
  
      Returns:
          The expression resulting from applying the substitution.