To understand what has happened, let's just define:
ClearAll[f];
SetAttributes[f, {Flat}];
f[x_] := Hold[x];
f[1]
(*Returns Hold[f[1]]*)
The reason for this extra f
in the output is that for a Flat
symbol expressions f[x]
and f[f[x]]
are identical. So, when a pattern-matcher encounters f[1]
it treats the expression as f[f[1]]
and consequently substitutes f[1]
, not 1
, instead of x
in the rhs of the definition. The pattern matcher prefers f[f[1]]
over f[1]
when matching x_
to allow for matching a sequence of arguments as a whole:
f[1, 2]
(*Returns Hold[f[1, 2]]*)
Here the pattern matcher treated f[1, 2]
as f[f[1, 2]]
and replaced x
by f[1, 2]
accordingly.
As chuy has already mentioned in the comments, you can add OneIdentity
attribute to a symbol. Then the pattern-mathcer will prefer f[1]
over f[f[1]]
when matching f[x_]
if there is only one argument inside the expression:
ClearAll[f];
SetAttributes[f, {Flat, OneIdentity}];
f[x_] := Hold[x];
f[1]
f[1, 2]
(*Returns Hold[1] and Hold[f[1, 2]]*)
Note, however, that OneIdentity
attribute will not save your form recursion when there are more than one argument: f[1, 2]
will be matched as f[f[1, 2]]
, f[1, 2]
will be squared, f[1, 2]^2
, and the f[1, 2]
inside the square will again be matched as f[f[1, 2]]
. So, basically, use Flat
attribute only for symbols which really stand for some associative operators or you are likely to get into trouble.
ClearAll[f];
SetAttributes[f, {Flat, OneIdentity}];
f[x_] := x^2;
f[1]
f[1, 2]
(*1
$RecursionLimit::reclim2 bla-bla-bla
Hold[f[1, 2]^2]
*)
fonction[x]
, you likely want to add the AttributeOneIdentity
. $\endgroup$ – chuy Dec 31 '18 at 17:28