2
$\begingroup$

I am trying to use functions with the same name, but which do different stuff. Let me show an example.

predef[x_] := x^3 - x^2 + 2x -1;
g[x_,y_] := x^2 + 2 x y - y +3;      
func[] := Print[predef[4]];
func[f_[x_,y_]] := Print[f[2, 3]];
func[list_] := Print[list[[4]]];

Now the first func call returns returns 55; fine.
The last call works fine too, but the second call using the g function as a parameter returns 2x y, but I have expected it to return 16.
What’s going on here?

$\endgroup$
  • 2
    $\begingroup$ You need to add SetAttributes[func, HoldFirst] to avoid evaluation of g[x, y] in the function call. $\endgroup$ – MarcoB May 29 '18 at 13:55
2
$\begingroup$

The situation becomes more clear if you trace the evaluation of func[g[x, y]]:

ClearAll[func]
func[] := Print[predef[4]]
func[f_[x_, y_]] := Print[f[2, 3]]
func[list_] := Print[list[[4]]]

Trace@func[g[x, y]]

(* Out: {
 {HoldForm[g[x, y]], HoldForm[x^2 + 2*x*y - y + 3], HoldForm[3 + x^2 - y + 2*x*y]}, 
  HoldForm[func[3 + x^2 - y + 2*x*y]], 
  HoldForm[Print[(3 + x^2 - y + 2*x*y)[[4]]]], 
  {HoldForm[(3 + x^2 - y + 2*x*y)[[4]]], HoldForm[2*x*y]}, HoldForm[Print[2*x*y]], 
  .... }
*)

You see here that the first thing that happens during evaluation is that g[x, y] is evaluated to its value, i.e. x^2 + 2*x*y - y + 3.

The definition of func that applies then is the last one now, i.e. func[list_] := Print[list[[4]]] because that's the only one that applies to the polynomial passed to func, which is an expression with head Plus, which to Mathematica matches the list_ pattern.

The evaluation then continues to HoldForm[Print[(3 + x^2 - y + 2*x*y)[[4]]]], which prints the fourth part of the polynomial expression, which happens to be 2 x y.


To avoid this you need to prevent premature evaluation of your function's arguments. This is what the Hold attributes do. In this case, you could use HoldFirst to hold the first argument unevaluated:

ClearAll[func]
func[] := Print[predef[4]]
func[f_[x_, y_]] := Print[f[2, 3]]
func[list_] := Print[list[[4]]]
SetAttributes[func, HoldFirst]

func[g[x, y]]
(* out: 16 *)

You can see now the difference by tracing the evaluation:

Trace@func[g[x, y]]

(* Out: 
{func[g[x, y]],
 Print[g[2, 3]], 
 {g[2, 3], 
   2^2 + 2 2 3 - 3 + 3, 
   {2^2, 4}, {2 2 3, 12}, {-3, -3}, 4 + 12 - 3 + 3, 16}, 
 Print[16], ...}
*)

Additionally, I would also suggest that you restrict the last definition of your function to match only inputs that are explicitly lists:

ClearAll[func]
func[] := Print[predef[4]]
func[f_[x_, y_]] := Print[f[2, 3]]
func[list_List] := Print[list[[4]]] (*notice the _List restriction *)
SetAttributes[func, HoldFirst]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.