0
$\begingroup$

I am constructing functions that call on multiple other functions and I want to understand how the ordering of evaluation of functions works and what is the best practice when writing many component functions.

Take this example nested function (and assume they are complicated enough that writing it as one big function might be undesirable).

ClearAll["Global`*"];
aList[x_, y_] := Piecewise[{
   {{a , b , c }, x > y},
   {{d , e , f }, True}
   }]
blist[x_, y_] := aList[x, y]*{1, 2, 3}
blist[1, 2]
blist[w, v]
blist[w, v] // ReplaceAll[#, {w -> 1, v -> 2}] &

blist[1, 2] gives the desired/'correct' output : {d, 2 e, 3 f}

However, the unevaluated/general form blist[w, v] pushes the piecewise function into {1,2,3} so that when the general form is called and then evaluated (for example in a graph) as in

blist[w, v] // ReplaceAll[#, {w -> 1, v -> 2}] &, it gives the 'incorrect' 3x3 matrix: {{d, e, f}, {2 d, 2 e, 2 f}, {3 d, 3 e, 3 f}}

Apart from pushing {1,2,3} into the aList function, which might be difficult for readability for complex functions, I attempted 2 fixes:

FIX 1:

clist[x_, y_] := Hold[aList[x, y] {1, 2, 3}]
clist[1, 2] // ReleaseHold
clist[w, v]
clist[w, v] // ReplaceAll[#, {w -> 1, v -> 2}] &
clist[w, v] // ReplaceAll[#, {w -> 1, v -> 2}] & // ReleaseHold

I am not familiar with Hold, but this seems to work? But is this advisable? Should all functions be held just in case? Does this affect performance?

FIX 2:

dlist[x_, y_] := aList[x, y].DiagonalMatrix[{1, 2, 3}]
dlist[1, 2]
dlist[w, v]
dlist[w, v] // ReplaceAll[#, {w -> 1, v -> 2}] &

Specifying it as a matrix doesn't trigger the problem, though it is not clear to me why * and . are operating differently.

Attributes[Times] and Attributes[Dot] doesn't indicate anything about Holds.

$\endgroup$
  • $\begingroup$ Some thoughts ... Times has Listable attribute (threads over list), so it automatically makes element-wise multiplication of unevaluated (with symbolic input) aList and a list {1,2,3}, that is the reason you see 3x3 matrix as output. You can use With to inject numeric values: blist[x_, y_] := With[{x1 = x, y1 = y}, aList[x1, y1] {1, 2, 3}] or use Unevaluated like this: clist[x_, y_] := Unevaluated[aList[x, y] {1, 2, 3}]. You can always use Trace to see how evaluation is going. $\endgroup$ – Alx Jan 2 at 3:25

Your Answer

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

Browse other questions tagged or ask your own question.