6
$\begingroup$

I just learned in this answer that you can put conditions inside a With and thus use computed values in them, like this:

f[x_] := With[{y = x^2}, y-2 /; y > 2]
f[2]
(*
==> 2
*)
f[1]
(*
==> f[1]
*)

A few tests show that it also works with Module and Block, and also in cases like this:

g[x_] := Module[{y=x}, Print["Test"]; y /; y == 1]

On the other hand, the following does not work:

SetAttributes[myblock,HoldAll]
myblock[v1_, v2_, expr_] := Block[{v1 = v2}, expr]
foo[x_] := myblock[a, x^2, a-1 /; a >= 1]
foo[0]
(*
==> -1 /; a >= 1
*)

Therefore I wonder: What are the exact rules where the condition can be put?

$\endgroup$
8
$\begingroup$

The reason your last example does not work is that the condition is only interpreted as shared between the body and the signature, when it literally appears within Block, Module, or With at the time the definition is created. In your last example, you effectively postpone the insertion of Condition until run-time, into your newly defined scoping construct, and therefore this doesn't work (because the pattern matcher fails to recognize this as a conditional rule, see below).

In my implementation of LetL macro, I had to take this issue into consideration, which is why LetL was implemented as a macro (so it expands at run-time), and has a special definition for SetDelayed, to expand before SetDelayed actually creates a definition. A more detailed discussion in the context of LetL can be found here.

So, the moral of the story is that if you want to construct your own scoping constructs, which are equivalent to some nested combination of Module, Block or With, with the semantics of shared variables, then you have to expand that code at run-time to actual combination, before creating a definition (so that your scoping construct should then necessarily be a macro, rather than a normal function). And, you can't generalize this mechanism to a scoping construct with the head other than With, Module or Block, to be called at run-time with this semantics.

Heuristically, this can be easily understood, because such conditions with shared variables are treated specially by the pattern-matcher, but how would a pattern-matcher know that this is some such, looking only at the left-hand-side, if you have encoded such a construct into some user-defined head, which only evaluates when the r.h.s. of the rule evaluates? This is not possible.

$\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.