2
$\begingroup$

This seems like an obvious issue that I have nevertheless never encountered before.

In a package, I want to use a variable to define a pattern that is used in the definition of some functions. However the actual pattern is not defined until run-time. Unfortunately MMA refuses to use the updated values in the variable, and the function definitions retain the original symbol definition that was set within the package. The function 'Update' is of no assistance:

ClearAll[testF,$symbols]
$symbols="placeholder";

testF[$symbols]:="It works!!!"
testF[___]:="Failed!!!"

(*Sometime later, after the package has been loaded, a new definition of $symbols is made:*)
$symbols=Alternatives@@{a,b,c};

(* However it is clear that the updated $symbols is not being used, the "placeholder" 
value having been inserted, and $symbol not appearing at all within the DownValues:*)
DownValues[testF]
(*-> {HoldPattern[testF["placeholder"]]:>"It works!!!", HoldPattern[testF[_]]:>"NO!!!"} *)

(*And of course it is impossible for testF[a] to work as expected:*)
testF[a]
(*-> "NO!!!" *)

(* 'Update' is useless: *)
Update[testF]
Update[$symbols]
(* -> syntax errors for Update[$symbols] because the Alternatives are inserted.*)

(* Downvalues of 'testF' are unchanged, and the function still fails: *)
testF[a]
(*-> "NO!!!" *)

Of course all works fine if the first $symbols definition ($symbols="placeholder";) is just replaced with the second, but that just defeats the purpose. I want the testF definition to inherit the changes to $symbols.

Q: How to get $symbols to be retained in its symbolic form within the testF DownValues so that when I update from 'placeholder' to the Alternatives ($symbols=Alternatives@@{a,b,c};) then testF reflects the changes?

$\endgroup$
4
  • 1
    $\begingroup$ You will notice that the DownValues of testF contains no $symbols. When you evaluated testF[$symbols] := "It works!!!", $symbols was evaluated to be "placeholder" and therefore testF is defined in terms of "placeholder". You haven't specified what behavior you want. So, specifically, after $symbols=Alternatives@@{a,b,c} what do you want testF to return then? I suspect that you want to use $symbols on the right-hand side of your definition of testF, but you need to explain to us the behavior you want. $\endgroup$
    – lericr
    Sep 24, 2022 at 0:38
  • $\begingroup$ Thanks @lericr, I have updated, hopefully a bit more clear now. $\endgroup$ Sep 24, 2022 at 1:10
  • $\begingroup$ You still haven't indicated the desired behavior. Look, if testF somehow depends on $symbols, then write it that way. Somethinng like testF[] := Switch[Head[$symbols], String, "it works with string", Alternatives, "it works with alternatives", _, "i don't handle that form"] $\endgroup$
    – lericr
    Sep 24, 2022 at 1:26
  • $\begingroup$ The desired behavior is that testF[a] returns "It works!". The problem is that the definition viz $symbols is inserted immediately when testF is defined. There is no way to force it to be retained in symbolic form except by putting it inside of a Condition statement. $\endgroup$ Sep 24, 2022 at 1:34

2 Answers 2

3
$\begingroup$

If I'm understanding the semantics, you want to define testF as:

if the single argument matches the expression currently saved as $symbols, then return "It works!!!"; otherwise return "Failed!!!"

I don't really see the need for dynamically updating the DownValues of testF. The use of Condition described in the other answer apparently works, but one could just follow the semantics as I described it above.

testF[arg_] := If[MatchQ[arg, $symbols], "It works!!!", "Failed!!!"]

Having said that, I'm not a fan of mysterious side effects. If I had more information about why you're doing this, I could probably propose a more purely functional approach.

$\endgroup$
2
  • $\begingroup$ +1 especially for "not a fan of mysterious side effects". $\endgroup$
    – user293787
    Sep 24, 2022 at 9:01
  • $\begingroup$ Thanks @lericr. I think the advantage of having the originally wished for pattern of testF[$symbols]:="OK" is that it represents a standard MMA pattern (testF[a|b]:="OK") and that it would presumably be faster than the Condition version of the pattern. Your design here is of course fine, but it would not seem to be the most MMA colloquial (a minor gripe, certainly). More importantly though, I would expect it to be slower than the pure pattern-based versions (although I have not benchmarked it). $\endgroup$ Sep 24, 2022 at 14:20
3
$\begingroup$

Perhaps better answers will come, but I have found two on my own:

The easy answer: One cannot use 'variable patterns' ($symbols) 'directly' within the LHS of function definitions (i.e. testF[$symbols]:="...") because of the issues described in the OP. (What the scope of the 'directly' constraint is not entirely clear). However MMA magically retains 'variable patterns' in their original symbolic forms within a Condition on the LHS. Hence one can write:

testF[x_/;MatchQ[x,$symbols]]:="It works!!!"

and the DownValues will still contain $symbols:

DownValues[testF]
(*-> {HoldPattern[testF[x_/;MatchQ[x,$symbols]]]:>"It Works!",...}

That is, the Condition protected the values of $symbols from being immediately inserted.

The hard answer: One has to redefine the DownValues on-the-fly at runtime. This is not a practical solution.

EDIT: in fact the issue is a bit more subtle: it is not just that the values of the $symbols symbol are being inserted 'prematurely'. Even if $symbols is not given any value prior to the definition of testF so that it is retained and visible within the LHS of the testF DownValues replacement rule, even then it will not be evaluated such that any current values are inserted. Yet somehow MMA will evaluate that same symbol if it is within Condition.

$\endgroup$
8
  • 1
    $\begingroup$ No, it doesn't seem funny. Condition has the attribute HoldAll. So does PatternTest, so you could have also done this: testF[x_?(MatchQ[$symbols])]:=.... This behavior is totally expected. $\endgroup$
    – lericr
    Sep 26, 2022 at 14:46
  • 1
    $\begingroup$ And no, the objective is not clear, and doesn't seem to be simple. You've just provided a bit more with your comment about "running for hours and updating symbols", but you seem stuck on the mechanism of using a single SetDelayed expression to be able to repeatedly trigger changes to DownValues. That's not a clear objective, that's a very specific strategy for implementing an as yet unstated objective. There may actually be a clever way to do this, but I won't hazard a guess without understanding more about the objective. $\endgroup$
    – lericr
    Sep 26, 2022 at 14:48
  • 1
    $\begingroup$ Let's start simpler. Assuming x is unassigned, evaluating testFunc[x] := 5 results in DownValues of HoldPattern[testFunc[x]] :> 5. HoldPattern has the HoldAll attribute. The evaluator uses the DownValues to find matching expressions. Expressions are checked against the left-hand-side of the rule, and upon finding a match, the right-hand-side is used as the replacement. Once that right-hand-side is "free" of the HoldPattern, it will itself undergo matching/replacing cycles by the evaluator. We can see if it works: testFunc[x] should return 5. ... $\endgroup$
    – lericr
    Sep 27, 2022 at 16:14
  • 1
    $\begingroup$ Now evaluate x = 17 and then testFunc[x]. The result is testFunc[17]. Why? Before the evaluator tries to replace the whole expression, it first evaluates the arguments. The symbol x gets replaced with 17 and there is no more work to be done on the arguments. The evaluator moves on to evaluating testFunc[17], but it finds no match. The integer 17 does not match the symbol x. Remember, the DownValues pattern we're matching against, testFunc[x], is being held by HoldPattern. With no match, there is no more work to do, and we're left with testFunc[17]. $\endgroup$
    – lericr
    Sep 27, 2022 at 16:20
  • 1
    $\begingroup$ With this, you can now try to analyze your tF[a:$S,b_/;MatchQ[b,$S]]:={a,b} situation. It's not a matter of which function properties are blocking evaluation, but a more fundamental matter of the rules of evaluation. $\endgroup$
    – lericr
    Sep 27, 2022 at 16:23

Your Answer

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

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