1
$\begingroup$

I have two complicated functions f[x,y] and g[t].

Before the main evaluation code in g[expr], I run some computationally expensive tests to check that expr has correct syntax. If expr does not have correct syntax, it gives an error to the user. But otherwise, it continues.

Now, the output of f[x,y] can be used as input of g (as in g[f[x,y]]). The result of f[x,y] is usually very very complicated, but always has correct syntax for the function g. Thus to save time I want to bypass the computationally expensive but pointless checks in g.

For this I invented a tag: $needsErrorChecking, which is supposed to by switched to False if f and g are called in the nested form g[f[x,y]]. Otherwise it is True, in which case the error checking routines take place.

Here is my toy example:

Clear[f, g]
 f[x_, y_] := x + y

$needsErrorChecking = True;
    g[f[z__]] ^:= "Nothing" /; ($needsErrorChecking = False);
    g[t_] := Module[{variables}, Print[$needsErrorChecking];
   If[$needsErrorChecking,(*Complicated Code*) Null, $needsErrorChecking = True]; 2*t];

However, Running

g[f[x, y]]

yields True and 2(x+y). So it gives the correct answer, but the error checking code isn't bypassed. What can I do to fix this?

Or, is there a totally different way to go about accomplishing this task?

$\endgroup$

2 Answers 2

1
$\begingroup$

You can make your scheme work by setting the HoldAll attribute on g:

SetAttributes[g, HoldAll]

Without it, g[f[x, y]] evaluates the f expression before g gets a chance to look at it. Thus, the "Nothing" definition never kicks in and $needsErrorChecking is never cleared.

Alternative

A simpler way to achieve this effect is as follows:

Clear[f, g]
f[x_, y_] := x + y

SetAttributes[g, HoldAll]

g[t_f] := fastG[t]
g[t_] := Module[{variables}, Print@"perform check"; fastG[t]]
fastG[t_] := 2 * t

Then:

g[f[1, 2]]

(* 6 *)

and:

g[3]

(*
   perform check
   6
*)
$\endgroup$
1
$\begingroup$

If the special case that does not deserve checks comes only out of function f, then I would try the following code instead of using tags. The basic idea is to use the head of the unevaluated expression as the "tag".

SetAttributes[g, HoldFirst];
g[f[z__]] := (Print["no checks here"]; Sqrt[f[z]]);
g[t_] := (Print["checks here"]; Sqrt[t]);
f[x_, y_] := x^2 + y^2

The output of g[4] and g[f[1,2]] yield respectively the expected checking version and non-checking version.

If the special case that does not deserve checks comes from more than a handful of functions, I would use something based on OptionsPattern.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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