To solve the given optimization problem, we first need to convert the natural language description into a symbolic representation. This involves defining variables for the quantities of Sandwich A and Sandwich B to be produced, expressing the objective function in terms of these variables, and formulating the constraints based on the available cheese.

Let's denote:
- \(x_1\) as the number of Sandwich A to be made,
- \(x_2\) as the number of Sandwich B to be made.

The objective is to maximize profit. Given that Sandwich A yields a profit of $5 per unit and Sandwich B yields a profit of $6 per unit, the objective function can be written as:
\[ \text{Maximize:} \quad 5x_1 + 6x_2 \]

The constraints are based on the availability of cheddar and American cheese:
- Each Sandwich A requires 3 units of cheddar cheese, and each Sandwich B requires 5 units. The shop has 500 units of cheddar cheese available. Thus, the constraint for cheddar cheese is: \(3x_1 + 5x_2 \leq 500\).
- Each Sandwich A requires 3 units of American cheese, and each Sandwich B requires 2 units. The shop has 400 units of American cheese available. Thus, the constraint for American cheese is: \(3x_1 + 2x_2 \leq 400\).

Additionally, the number of sandwiches cannot be negative, so we have:
- \(x_1 \geq 0\)
- \(x_2 \geq 0\)

The symbolic representation in JSON format is:
```json
{
    'sym_variables': [('x1', 'Number of Sandwich A'), ('x2', 'Number of Sandwich B')],
    'objective_function': '5*x1 + 6*x2',
    'constraints': ['3*x1 + 5*x2 <= 500', '3*x1 + 2*x2 <= 400', 'x1 >= 0', 'x2 >= 0']
}
```

Now, let's implement this optimization problem using Gurobi in Python:

```python
from gurobipy import *

# Create a new model
m = Model("Sandwich_Optimization")

# Define the variables
x1 = m.addVar(vtype=GRB.CONTINUOUS, name="Sandwich_A", lb=0)
x2 = m.addVar(vtype=GRB.CONTINUOUS, name="Sandwich_B", lb=0)

# Set the objective function
m.setObjective(5*x1 + 6*x2, GRB.MAXIMIZE)

# Add constraints
m.addConstr(3*x1 + 5*x2 <= 500, "Cheddar_Cheese_Constraint")
m.addConstr(3*x1 + 2*x2 <= 400, "American_Cheese_Constraint")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found.")
    print(f"Number of Sandwich A: {x1.x}")
    print(f"Number of Sandwich B: {x2.x}")
    print(f"Maximum Profit: ${5*x1.x + 6*x2.x:.2f}")
else:
    print("No optimal solution found.")
```