Using the HoldAll attribute mentioned by ninjagecko, I was able to create a solution.
In fact, there was another problem that I could not immediately see. In particular, my function was not pattern matching, as I thought it would be.
I thought my initial question was simply that Mathematica automatically simplified my expressions, and I needed to lazily evaluate the parameters passed for the correct behavior.
In fact, I forgot that there are several ways to represent expressions in Mathematica. As an example of toys, consider the following function, which extracts the numerator and denominator of a fraction:
ExtractNumDem[Fraction[a_, b_]] := {a, b} (* Already incorrect, ExtractNumDem[4 / 100] gives {1, 25} *)
Just adding the HoldAll attribute (or HoldFirst even) leads to another problem:
SetAttributess[ExtractNumDem, HoldAll]; ExtractNumDem[4 / 100] (* Gives ExtractNumDem[4 / 100] *)
The 4/100 expression actually evaluates Times[4, Power[100, -1]] . To fix this second problem, I had to add a definition for fractions that look like this:
ExtractNumDem[Times[a_, Power[b_, -1]] := {a, b} ExtractNumDem[4/100] (* Now gives {4, 100} *)
My solution to the problem in my original answer applied the same exact principle. Here is some code to see the problem I encountered:
ClearAll[ExtractNumDem] ExtractNumDem[Rational[a_, b_]] := {a, b} ExtractNumDem[4 / 100] SetAttributes[ExtractNumDem, HoldAll]; ExtractNumDem[4 / 100] ExtractNumDem[Times[a_, Power[b_, -1]]] := {a, b} ExtractNumDem[4/100]