changing number of arguments to a function in secondary evaluation

From my own comment:

You're mixing the concepts of pure functions (# and &) with replacement (/., ->, :>). Use slots with the first one, use patterns (Pattern in the documentation, x_ or x__ for example in usage) with the second.

For this problem:

f[a, b, c, d] /. f[x__] :> g[x, e]

g[a, b, c, d, e]

Note the use of __, which is two underscores: This is a pattern which grabs 1 or more elements (see also ___ which grabs 0 or more elements), and inserts them as a Sequence when used in replacement. Thus, it doesn't get inserted as a List.

If you wanted to do this with pure functions, it becomes a bit more complicated:

g[Sequence @@ #, e] &[f[a, b, c, d]]

g[a, b, c, d, e]

But note that this isn't dependent on its argument being in the form of f[...], it will replace any functional head. To avoid that requires conditionals of some variety, e.g:

If[Head[#] === f, g[Sequence @@ #, e], Undefined] &[f[a, b, c, d]]

You can also use Apply:

g[##, e] & @@ f[a, b, c, d]

g[a, b, c, d, e]

or ReplaceAll with replacement rule f -> (g[##, e] &):

f[a, b, c, d] /.  f -> (g[##, e] &)

g[a, b, c, d, e]


There is yet another solution, using Flatten with Head f, namely

Flatten[g[f[a, b, c, d], e], 1, f]

g[a, b, c, d, e]

This assumes that g is not defined for two arguments, otherwise it will evaluate before Flatten has a chance so flatten the f. If that's not the case one can use Inactive on g, act with Flatten and then Activate again.

Activate[Flatten[Inactive[g][f[a, b, c, d], e], 1, f]]