I am building a tool to manipulate Feynman diagrams and depict them using the Graph functionality. A diagram might have the following syntax
f=diag[g[a,i[1]],g[b,i[2]],g[i[1],c],g[i[2],d],v[i[1],i[2]]]
This is just an example. Now we would like to represent it as a graph.
First way (using RuleDelayed):
Clear[pic]
pic[diag[x__]]:=Module[{i},Graph[List[x]/.{g[i_,j_]:> DirectedEdge[j,i],v[j_,k_]:> UndirectedEdge[j,k]},VertexLabels->"Name",PlotTheme->"Business",ImageSize->300,ImagePadding->10,VertexLabelStyle->Directive[Black,11],GraphHighlight->Cases[List[x],v[i_,j_]:> UndirectedEdge[i,j]]]]
Using it
pic[f]
i=5;
pic[f]
produces
Thus we have an expected result and a result with wrong labels.
Second way (using Rule)
Clear[i,g,v,f]
f=diag[g[a,i[1]],g[b,i[2]],g[i[1],c],g[i[2],d],v[i[1],i[2]]];
Clear[pic]
pic[diag[x__]]:=Module[{i,j,k},Graph[List[x]/.{g[i_,j_]->DirectedEdge[j,i],v[j_,k_]->UndirectedEdge[j,k]},VertexLabels->"Name",PlotTheme->"Business",ImageSize->300,ImagePadding->10,VertexLabelStyle->Directive[Black,11],GraphHighlight->Cases[List[x],v[i_,j_]->UndirectedEdge[i,j]]]]
Now using it
pic[f]
i=5;
pic[f]
Produces the correct picture only the first time, and does not work at all second time.


RuleDelayedsolves your problem in the second snippet. It is true thatRuletreats named pattern as local to the rule. However in the second snippet, the right-hand side gets evaluated toTimes[2, 5]before any replacing takes place.RuleDelayedfirst performs replacements, and then evaluates the expression on the right-hand side of the rule. I am still confused about the first snippet, though. – Natas Oct 30 '20 at 10:55SetDelayedis not relevant here. The confusing part is this:Clear[i, x]; i = n; Module[{i}, x /. {i_ -> i}] (*n*). To be honest, if this is expected behavior I have understood nothing aboutModule. – Natas Oct 30 '20 at 11:03Moduleis this "Before evaluating expr, Module substitutes new symbols for each of the local variables that appear anywhere in expr except as local variables in scoping constructs." The issue now is thatRuleis also a scoping construct (with named patterns). ThereforeModuledoes not replace theiin theRule. – Natas Oct 30 '20 at 11:10RuleDelayed. This would be the "canonical way" in my opinion. – Natas Oct 30 '20 at 11:13Ruleinstead ofRuleDelayed. In the first the problem for the label is thatfis defined usingi. Of course, if you later setiit will be used for the value off. Mathematica usually evaluates expressions unless being told to hold them. – Natas Oct 30 '20 at 11:29iin the first way. – yarchik Oct 30 '20 at 11:31fwould useDownValuesandSetDelayed. – Natas Oct 30 '20 at 11:34f. The thing is I am doing something similar like you said, but it does not change anything. – yarchik Oct 30 '20 at 11:39Protectthe special symbols to prevent any assignment to them. There just isn't any easy solution too scoping in programming. If you want to do it right, it takes a lot of time and patience. – Natas Oct 30 '20 at 11:46Graphexample: 1. 2.Moduleonly sees explicit variable:Clear[a, b, c]; b = 2 a; Module[{a = 2}, b], soModulejust won't help here.Blockmay be a choice for circumventing. 2. Function withoutHold*attribute evaluates its argument before it's passed into the function. Example:Clear[f, i]; f[x_] := Block[{i}, Hold[x]]; i = 2; {f[i], f[Unevaluated@i]}, so yourihas already evaluated to5before passing into the function. – xzczd Oct 30 '20 at 12:16Clear[i, pic]; f = diag[g[a, i[1]], g[b, i[2]], g[i[1], c], g[i[2], d], v[i[1], i[2]]];pic[diag[x__]] := Graph[{x} /. {g[i_, j_] :> DirectedEdge[j, i], v[j_, k_] :> UndirectedEdge[j, k]}, VertexLabels -> "Name"];i = 5;Block[{i = "i"}, pic[f]]– xzczd Oct 30 '20 at 12:21