I am trying to define a replacement rule with optional argument color_RGBColor which should be replaced with Sequence[] when it is absent in the original expression:
style[line_Line, ___,
color_RGBColor: Unevaluated#Sequence[], ___] :> {color, line}
When RGBColor is present in the original expression, the rule works:
style[Line[], RGBColor[{}]] /.
style[line_Line, ___,
color_RGBColor: Unevaluated#Sequence[], ___] :> {color, line}
=> {RGBColor[{}], Line[]}
But when it is absent, it does not:
style[Line[], Thickness[0.01]] /.
Style[line_Line, ___,
color_RGBColor: Unevaluated#Sequence[], ___] :> {color, line}
=> style[Line[], Thickness[0.01]]
My questions are:
1) Why it does not work?
2) Is it possible to construct a single pattern which will work as desired?
Your pattern does not work because of the way the pattern-matching works for the default (optional) arguments, and also because you restricted the head to be RGBColor. The problem is that the default argument value must match the pattern, while Unevaluated[Sequence[]] certainly does not match _RGBColor.
You have several ways out. A first attempt is to weaken your type-checking:
In[10]:= style[Line[],Thickness[0.01]]/.
style[line_Line,___,color_: Unevaluated#Sequence[],___]:>{color,line}
Out[10]= {Thickness[0.01],Line[]}
But this does not work since the matching is incorrect - the typing is indeed too weak. The hacky way to make it work is this:
In[14]:= style[Line[], RGBColor[{}]] /.
style[line_Line, ___, color : (_RGBColor | _Unevaluated) :
Unevaluated#Sequence[], ___] :> {Evaluate#color, line}
Out[14]= {RGBColor[{}], Line[]}
In[15]:= style[Line[], Thickness[0.01]] /.
style[line_Line, ___, color : (_RGBColor | _Unevaluated) :
Unevaluated#Sequence[], ___] :> {Evaluate#color, line}
Out[15]= {Line[]}
The recommended way to do it is this:
In[18]:= style[Line[], Thickness[0.01]] /.
style[line_Line, ___, color : (_RGBColor | Automatic) : Automatic, ___] :>
If[color === Automatic, {line}, {color, line}]
Out[18]= {Line[]}
In[17]:= style[Line[], RGBColor[{}]] /.
style[line_Line, ___, color : (_RGBColor | Automatic) : Automatic, ___] :>
If[color === Automatic, {line}, {color, line}]
Out[17]= {RGBColor[{}], Line[]}
This feature of the pattern-matcher is not very widely known, so I will stress it again: the default value for the (optional) pattern x:ptrn:default must match ptrn. For another example of such behavior, see this Mathgroup discussion.
Perhaps this works for you:
style[Line[a], RGBColor[{}]] /.
style[line_Line, ___, Longest[color___RGBColor], ___] :> {color,line}
(*
{RGBColor[{}], Line[a]}
*)
style[Line[]] /.
style[line_Line, ___, Longest[color___RGBColor], ___] :> {color, line}
(*
{Line[]}
*)
I guess your replacement rule does not work just because there is no element with a Head RGBColor, so there is no match.
Related
What is the simplest way to make an analog of MakeBoxes which will reproduce only on aspect of its behavior: converting correct expressions involving only symbols without FormatValues to BoxForms:
Trace[MakeBoxes[graphics[disk[]], StandardForm], TraceInternal -> True]
This function should be recursive as MakeBoxes is. What is really confusing is how to convert disk[] to RowBox[{"disk", "[", "]"}] avoiding parsing of string representation of the original expression.
P.S. This question comes from the previous question.
I don't think you can avoid parsing or string conversion in one way or another - at the end you need strings, and you start with symbols. Either you somehow reuse MakeBoxes, or you have to deal with strings. Dragging my code around: the following simple box-making function is based on the Mathematica parser posted here (my second post there, at the bottom of the page):
Clear[toBoxes];
toBoxes[expr_] :=
First[parse[tokenize[ToString#FullForm[expr]]] //. {
head_String[elem_] :> RowBox[{head, "[", elem, "]"}],
head_String[elems___] :> RowBox[{head, "[", RowBox[Riffle[{elems}, ","]], "]"}]}]
If you don't want to parse but don't mind ToString, then a slight variation of the above will do:
toBoxesAlt[expr_] :=
expr /. s_Symbol :> ToString[s] //. {
head_String[elem_] :> RowBox[{head, "[", elem, "]"}],
head_String[elems___] :> RowBox[{head, "[", RowBox[Riffle[{elems}, ","]], "]"}]}
Note that this last function does not involve any parsing.Then, we need:
Clear[MakeBoxesStopAlt];
MakeBoxesStopAlt /: MakeBoxes[MakeBoxesStopAlt[expr_], form_] := toBoxes[expr]
For example:
In[327]:= MakeBoxesStopAlt[Graphics[Disk[]]]
Out[327]= Graphics[Disk[List[0, 0]]]
You may want to re-implement the parser if my implementation looks too complicated, although mine is rather efficient.
EDIT
Here is a very simplistic and probably slow approach to parsing: the function tokenize is the same as before, and I will repost it here for convenience:
tokenize[code_String] :=
Module[{n = 0, tokenrules},
tokenrules = {"[" :> {"Open", ++n}, "]" :> {"Close", n--},
Whitespace | "" ~~ "," ~~ Whitespace | ""};
DeleteCases[StringSplit[code, tokenrules], "", Infinity]];
Here is the parsing function:
parseSimple[tokenized_] :=
First[tokenized //. {left___,
Shortest[
PatternSequence[h_, {"Open", n_}, elems___, {"Close", n_}]], right___} :>
{left, h[elems], right}];
You may use it in place of parse, and these two functions then form a self-contained solution for the parser.
The same comment as for my answer to your previous question is in order: if you want to handle /disallow expression evaluation, add appropriate attributes and Unevaluated wrappers where needed.
EDIT2
Here is a version of makeBoxes that does not involve parsing, does not leak evaluation and does handle nested heads correctly (at least for some simple tests):
Clear[handleElems];
handleElems[] := Sequence[];
handleElems[el_] := el;
handleElems[els__] := RowBox[Riffle[{els}, ","]];
ClearAll[makeBoxes];
SetAttributes[makeBoxes, HoldAllComplete];
makeBoxes[ex_] :=
Block[{makeBoxes},
SetAttributes[makeBoxes, HoldAllComplete];
makeBoxes[expr_ /;!FreeQ[Unevaluated[expr],
s_ /; AtomQ[Unevaluated[s]] && ! StringQ[Unevaluated[s]]]] :=
makeBoxes[#] &#(Unevaluated[expr] /.
s_ /; AtomQ[Unevaluated[s] && ! StringQ[Unevaluated[s]]] :>
ToString[Unevaluated[s]]);
makeBoxes[a_ /; AtomQ[Unevaluated[a]]] := a;
makeBoxes[expr_] /; MatchQ[expr, h_String[___]] :=
expr //. {
(h : ("Rule" | "RuleDelayed"))[l_, r_] :>
RowBox[{l, h /. {
"Rule" -> "\[Rule]",
"RuleDelayed" -> "\[RuleDelayed]"
}, r}],
"List"[elems___] :> RowBox[{"{", handleElems[elems], "}"}],
head_String[elems___] :> RowBox[{head, "[", handleElems[elems], "]"}]
};
makeBoxes[expr_] :=
RowBox[{makeBoxes[#] &#Head[expr], "[",
handleElems ## (makeBoxes ### expr), "]"}];
makeBoxes ## (HoldComplete[ex] /. s_String :>
With[{eval = StringJoin["\"", s, "\""]}, eval /; True])
];
Example of use:
In[228]:= a=1;b=2;c = 3;
In[229]:= makeBoxes[a:>b]
Out[229]= RowBox[{a,:>,b}]
In[230]:= makeBoxes[a->b]
Out[230]= RowBox[{a,->,b}]
In[231]:= makeBoxes[{a,{b,c}}]
Out[231]= RowBox[{{,RowBox[{a,,,RowBox[{{,RowBox[{b,,,c}],}}]}],}}]
In[232]:= makeBoxes[a[b][c]]
Out[232]= RowBox[{RowBox[{a,[,b,]}],[,c,]}]
In[233]:= makeBoxes[a[b[e[],f[]],c[g[],h[]]][x,y]]
Out[233]= RowBox[{RowBox[{a,[,RowBox[{RowBox[{b,[,RowBox[{RowBox[{e,
[,]}],,,RowBox[{f,[,]}]}],]}],,,RowBox[{c,[,RowBox[{RowBox[{g,[,]}],,,
RowBox[{h,[,]}]}],]}]}],]}],[,RowBox[{x,,,y}],]}]
In all cases tested, the output is the same as that of MakeBoxes.
Here is my implementation of simplified MakeBoxes without conversion of the original expression to string:
ClearAll[SimpleMakeBoxes, SimpleMakeBoxesRules];
SetAttributes[SimpleMakeBoxes, HoldAll];
SimpleMakeBoxesRules = {h_Symbol[] :> RowBox[{ToString#h, "[", "]"}],
h_Symbol[expr_] :>
RowBox[{ToString#h, "[", Unevaluated[expr] /. SimpleMakeBoxesRules, "]"}],
h_Symbol[expr__] :>
RowBox[{ToString#h, "[",
RowBox[Riffle[
List ## Replace[Hold[expr],
x_ :> (Unevaluated[x] /. SimpleMakeBoxesRules), {1}], ","]], "]"}],
a:(_Real | _Integer | _String) :> ToString[FullForm#a]};
SimpleMakeBoxes[expr_] :=
Unevaluated[expr] /.
SimpleMakeBoxesRules //. {RowBox[{"List", "[", elems___, "]"}] :>
RowBox[{"{", elems, "}"}],
RowBox[{"Rule", "[", RowBox[{lhs_, ",", rhs_}], "]"}] :>
RowBox[{lhs, "\[Rule]", rhs}],
RowBox[{"RuleDelayed", "[", RowBox[{lhs_, ",", rhs_}], "]"}] :>
RowBox[{lhs, "\[RuleDelayed]", rhs}]}
Usage example:
In[7]:= SimpleMakeBoxes#Graphics[Disk[]]
RawBoxes#%
Out[7]= RowBox[{Graphics,[,RowBox[{Disk,[,]}],]}]
Out[8]= Graphics[Disk[]]
How to get all definitions for a symbol associated with other symbols by TagSet, TagSetDelayed, UpSet or UpSetDelayed?
For example, if one has defined
area[square] ^= s^2
area[cube] ^= 6*s^2
how to obtain these definitions, not knowing the names square, cube but knowing only the name area?
I just have found that UpValues does not return definitions for MakeBoxes and N since they are stored in FormatValues and NValues correspondingly:
In[1]:= rotate /: MakeBoxes[expr_rotate, "StandardForm"] := x
UpValues[rotate]
FormatValues[rotate]
Out[2]= {}
Out[3]= {HoldPattern[MakeBoxes[expr_rotate, "StandardForm"]] :> x}
In[4]:= pi /: N[pi] = 3.14
UpValues[pi]
NValues[pi]
Out[4]= 3.14
Out[5]= {}
Out[6]= {HoldPattern[N[pi, {MachinePrecision, MachinePrecision}]] :>
3.14}
In this way instead of UpValues we should use a combination of UpValues, FormatValues and NValues.
When trying to output a list of FormatValues one can face problems with MakeBoxes since FormatValues gives definitions for MakeBoxes those are further processed by MakeBoxes on creating the output for the FrontEnd. This problem can be solved by switching FormatType temporarily to OutputForm or by converting these definitions to strings.
In[1]:= SetOptions[$Output,FormatType->OutputForm];
FormatValues[DialogNotebook]
Out[2]= {HoldPattern[MakeBoxes[BoxForm`apat$:HoldPattern[DialogNotebook[___]], BoxForm`fpat$_]] :>
BoxForm`BoxFormAutoLoad[MakeBoxes, BoxForm`apat$, BoxForm`fpat$, Typeset`CellNotebook`,
{{CellGroup, _}, {DocumentNotebook, _}, {PaletteNotebook, _}, {DialogNotebook, _}, {ExpressionCell, _}, {Text, _},
{TextCell, _}, {Cell, HoldPattern[MakeExpression[_Cell, _]]}, {Notebook, HoldPattern[MakeExpression[_Notebook, _]]}}]}
In[1]:= ToString#FormatValues[DialogNotebook]
Out[1]= {HoldPattern[MakeBoxes[BoxForm`apat$:HoldPattern[DialogNotebook[___]], BoxForm`fpat$_]] :> BoxForm`BoxFormAutoLoad[MakeBoxes, BoxForm`apat$, BoxForm`fpat$, Typeset`CellNotebook`, {{CellGroup, _}, {DocumentNotebook, _}, {PaletteNotebook, _}, {DialogNotebook, _}, {ExpressionCell, _}, {Text, _}, {TextCell, _}, {Cell, HoldPattern[MakeExpression[_Cell, _]]}, {Notebook, HoldPattern[MakeExpression[_Notebook, _]]}}]}
Attempting to address Alexey's concerns with Howard's answer, I came up with this:
Cases[
UpValues ### MakeExpression /# Names["Global`*"],
HoldPattern[_#_area :> _],
{2}
]
In response to your updated requirements, here is the advanced version:
SetAttributes[otherValues, HoldFirst]
otherValues[sym_] :=
With[{names = MakeExpression /# Names["Global`*"]},
Join[
Cases[UpValues ### names, HoldPattern[_#_sym :> _], {2}],
Cases[NValues ### names, HoldPattern[_#N[sym, ___] :> _], {2}],
Select[Join ## FormatValues ### names, ! FreeQ[#, HoldPattern#sym] &]
]
]
You can try an exhaustive search via
Select[UpValues /# Cases[ToExpression[Names["*"]], _Symbol], ! FreeQ[#, area] &]
which in your example will yield
{{HoldPattern[area[cube]] :> 6 s^2}, {HoldPattern[area[square]] :> s^2}}
The following version
Cases[
Flatten#Map[
ToExpression[#, InputForm, Function[sym, UpValues[sym], HoldAllComplete]] &,
Names["Global`*"]],
Verbatim[RuleDelayed][Verbatim[HoldPattern][_area], _]
]
will not evaluate symbols as well. It is similar in spirit to #Mr. Wizard's answer, but I prefer ToExpression to MakeExpression since the latter is tied to the FrontEnd and boxes ( at least conceptually) , while the former is a general-purpose command (although it is mentioned in the documentation that it will use rules for MakeExpression).
If you have an access to the full Mathematica session from the start, another solution would be to overload TagSet, TagSetDelayed, UpSet and UpSetDelayed so that they will record the symbol dependencies in some kind of hash. Here is an example for UpSet:
Unprotect[UpSet];
Module[{tried, upsetHash},
upsetHash[_] = {};
getUpsetHash[] := upsetHash;
UpSet[f_[args___], rhs_] :=
Block[{tried = True},
AppendTo[upsetHash[f],
Select[HoldComplete[args],
Function[Null, Head[Unevaluated[#]] === Symbol, HoldAll]]];
UpSet[f[args], rhs]] /; ! TrueQ[tried]
];
Protect[UpSet];
All assignments made with UpSet after this redefinition will be recorded. For example, after executing your example above, you can call
In[6]:= getUpsetHash[][area]
Out[6]= {HoldComplete[square], HoldComplete[cube]}
This way you get your information much faster, especially if you want to make such inquiries frequently, and/or you have lots of packages loaded. You can also automate the process further, to switch to the standard definitions for assignments once you load the functionality of interest.
Good day,
I'm puzzled a bit with this:
In[1]:= f[x_]:=With[{xx=x},f[xx_]:=ff[xx]]
DownValues[f]
f[1]
DownValues[f]
Out[2]= {HoldPattern[f[x_]]:>With[{xx=x},f[xx_]:=ff[xx]]}
Out[4]= {HoldPattern[f[xx_]]:>ff[xx]}
The same happens if I use Block or Module instead of With.
I expected that the last DownValues[f] will give: {HoldPattern[f[x_]]:>ff[x]}. But it does not. Please, explain.
From documentation of With.
With replaces symbols in expr only when they do not occur as local variables inside scoping constructs.
Module and Block are simply not meant to do it.
Edit to elaborate on Module and Block. `The reason symbol is not replaced, is that it is not being evaluated. Block and Module do not do syntactic replacement operations. Try
f[x_] := Block[{xx = x}, f[xx_] = ff[xx]]
and then evaluate f[z].
Alternatively, you can execute you initial strategy by first using non-scoping construct:
f[x_] := With[{xx = x},
Hold[{f[xx_], ff[xx]}] /. {Hold[{a_, b_}] :> SetDelayed[a, b]}]
In[117]:= DownValues[f]
Out[117]= {HoldPattern[f[x_]] :>
With[{xx = x},
Hold[{f[xx_], ff[xx]}] /. {Hold[{a_, b_}] :> (a := b)}]}
In[118]:= f[z]
In[119]:= DownValues[f]
Out[119]= {HoldPattern[f[z_]] :> ff[z]}
Say I have a list of Rules
rules = {a -> b, c -> d};
which I use throughout a notebook. Then, at one point, it makes sense to want the rules to apply before any other evaluations take place in an expression. Normally if you want something like this you would use
In[2]:= With[{a=b,c=d}, expr[a,b,c,d]]
Out[2]= expr[b, b, d, d]
How can I take rules and insert it into the first argument of With?
Edit
BothSome solutions fail do all that I was looking for - but I should have emphasised this point a little more. See the bold part above.
For example, let's look at
rules = {a -> {1, 2}, c -> 1};
If I use these vaules in With, I get
In[10]:= With[{a={1,2},c=1}, Head/#{a,c}]
Out[10]= {List,Integer}
Some versions of WithRules yield
In[11]:= WithRules[rules, Head/#{a,c}]
Out[11]= {Symbol, Symbol}
(Actually, I didn't notice that Andrew's answer had the Attribute HoldRest - so it works just like I wanted.)
You want to use Hold to build up your With statement. Here is one way; there may be a simpler:
In[1]:= SetAttributes[WithRules, HoldRest]
In[2]:= WithRules[rules_, expr_] :=
With ## Append[Apply[Set, Hold#rules, {2}], Unevaluated[expr]]
Test it out:
In[3]:= f[args___] := Print[{args}]
In[4]:= rules = {a -> b, c -> d};
In[5]:= WithRules[rules, f[a, c]]
During evaluation of In[5]:= {b,d}
(I used Print so that any bug involving me accidentally evaluating expr too early would be made obvious.)
I have been using the following form of WithRules for a long time. Compared to the one posted by Andrew Moylan, it binds sequentially so that you can say e.g. WithRules[{a->b+1, b->2},expr] and get a expanded to 3:
SetAttributes[WithRules, HoldRest]
WithRules[rules_, expr_] := ReleaseHold#Module[{notSet}, Quiet[
With[{args = Reverse[rules /. Rule[a_, b_] -> notSet[a, b]]},
Fold[With[{#2}, #1] &, Hold#expr, args]] /. notSet -> Set,
With::lvw]]
This was also posted as an answer to an unrelated question, and as noted there, it has been discussed (at least) a couple of times on usenet:
A version of With that binds variables sequentially
Add syntax highlighting to own command
HTH
EDIT: Added a ReleaseHold, Hold pair to keep expr unevaluated until the rules have been applied.
One problem with Andrew's solution is that it maps the problem back to With, and that does not accept subscripted variables. So the following generates messages.
WithRules[{Subscript[x, 1] -> 2, Subscript[x, 2] -> 3},
Power[Subscript[x, 1], Subscript[x, 2]]]
Given that With performs syntactic replacement on its body, we can set WithRules alternatively as follows:
ClearAll[WithRules]; SetAttributes[WithRules, HoldRest];
WithRules[r : {(_Rule | _RuleDelayed) ..}, body_] :=
ReleaseHold[Hold[body] /. r]
Then
In[113]:= WithRules[{Subscript[x, 1] -> 2,
Subscript[x, 2] -> 3}, Subscript[x, 1]^Subscript[x, 2]]
Out[113]= 8
Edit: Addressing valid concerns raised by Leonid, the following version would be safe:
ClearAll[WithRules3]; SetAttributes[WithRules3, HoldRest];
WithRules3[r : {(_Rule | _RuleDelayed) ..}, body_] :=
Developer`ReplaceAllUnheld[Unevaluated[body], r]
Then
In[194]:= WithRules3[{Subscript[x, 1] -> 2, Subscript[x, 2] -> 3},
Subscript[x, 1]^Subscript[x, 2]]
Out[194]= 8
In[195]:= WithRules3[{x -> y}, f[y_] :> Function[x, x + y]]
Out[195]= f[y_] :> Function[x, x + y]
Edit 2: Even WithRules3 is not completely equivalent to Andrew's version:
In[206]:= WithRules3[{z -> 2}, f[y_] :> Function[x, x + y + z]]
Out[206]= f[y_] :> Function[x, x + y + z]
In[207]:= WithRules[{z -> 2}, f[y_] :> Function[x, x + y + z]]
Out[207]= f[y$_] :> Function[x$, x$ + y$ + 2]
I have the expression D[f[x, y], x], and I want to substitute f[x,y] with x*y, I tried the following:
D[f[x, y], x] /. {f[x,y] -> x*y}
and
D[f[x, y], x] /. {f -> x*y}
But neither worked. Would appreciate your help! Thanks.
The FullForm of the derivative in your expression is
In[145]:= D[f[x,y],x]//FullForm
Out[145]//FullForm= Derivative[1,0][f][x,y]
This should explain why the first rule failed - there is no f[x,y] in your expression any more. The second rule failed because Derivative considers f to be a function, while you substitute it by an expression. What you can do is:
In[146]:= D[f[x,y],x]/.f->(#1*#2&)
Out[146]= y
Note that the parentheses around a pure function are essential, to avoid precedence - related bugs.
Alternatively, you could define your r.h.s through patterns:
In[148]:=
fn[x_,y_]:=x*y;
D[f[x,y],x]/.f->fn
Out[149]= y
HTH
Nothing new, just the way I usually think of it:
D[f[x, y], x] /. f -> Function[{x, y}, x y]
Out
y
You can also try Hold and Release or Defer etc.
Hold#D[f[x, y], x] /. {f[x, y] -> x*y}
D[x y, x]
Hold#D[f[x, y], x] /. {f[x, y] -> x*y} // Release
y