First of all, though SetDelayed
(:=
) has HoldAll
attribute, it still evaluates its 1st argument in this case, this behavior has been discussed in this post. To be specific, when test2
is defined, the argument ForAll[t, x_]
will be evaluated.
Now the question becomes
Why ForAll[t, x_]
evaluates to x_
?
and this has been explained in the Scope of the document of ForAll
:
If the expression does not explicitly contain a variable, ForAll
simplifies automatically:
ForAll[x, y == 0]
(* y == 0 *)
In your case, x_
doesn't explicitly contain t
, and it's automatically simplified, while t_
explicitly contain t
so it's not. (Notice the FullForm
of t_
is Pattern[t, Blank[]]
i.e. a function with 2 arguments whose 1st agrument is an explicit t
. )
To get the desired function definition, you can make use of Unevaluated
:
ClearAll@test2
test2[Unevaluated@ForAll[t, x_]] := x
DownValues@test2
(* {HoldPattern[test2[ForAll[t, x_]]] :> x} *)
test2[ForAll[t, t + t^2]]
(* t + t^2 *)
But notice this function still won't work as expected if the ForAll[…]
evaluates to something else, for example:
test2[ForAll[t, x]]
(* test2[x] *)
If you want it to evaluate to x
, then Unevaluated
again or as mentioned in the comment above, use HoldFirst
:
test2[Unevaluated@ForAll[t, x]]
(* x *)
SetAttributes[test2, HoldFirst]
test2[ForAll[t, x]]
(* x *)
HoldFirst
or similar attribute, otherwise it is the same as definingf[1+1]:=whatever
. $\endgroup$HoldFirst
for this method. I need it withoutHoldFirst
$\endgroup$test3[a_+b_]:=a
and it actually does work:?test3 (* => test3[a_+b_]:=a *)
$\endgroup$a_+b_
does not evaluate further whileForAll[t,x_]
does, tox_
. $\endgroup$ForAll
has noOptions
(specificallyHoldFirst
), and I think by default, it takes the symbol that's in the first argument and looks for it in the second argument. CompareForAll[x_, x_^2]
withForAll[x_, y_^2]
. The second evaluates toy_^2
because it has nox_
in it. $\endgroup$