开发者

Diciness with extracting things from a Hold'd expression

Suppose I have a list of param->value rules where the params are symbols that might have values assigned to them. For example:

{a, b, c} = {1, 2, 3};
x = Hold[{a->1, b->2, c->3}];

I need the list wrapped in Hold otherwise it would evaluate to {1->1, 2->2, 3->3}. (I'm open to any alternatives to Hold there if it makes the rest of this easier.)

Now suppose I 开发者_运维技巧want to convert x into this:

{"a"->1, "b"->2, "c"->3}

The following function will do that:

f[h_] := Block[{a,b,c}, ToString[#[[1]]]->#[[2]]& /@ ReleaseHold@h]

My question: Can you write a version of f where the list of symbols {a,b,c} doesn't have to be provided explicitly?


Here is a way using Unevaluated:

In[1]:= {a, b, c} = {1, 2, 3};

In[2]:= x = Hold[{a -> 1, b -> 2, c -> 3}];

In[3]:= ReleaseHold[
 x /. (symb_ -> e_) :> ToString[Unevaluated[symb]] -> e]

Out[3]= {"a" -> 1, "b" -> 2, "c" -> 3}


{a, b, c} = {1, 2, 3};
x = Hold[{a -> 1, b -> 2, c -> 3}];
f[x_] := Cases[x, HoldPattern[z_ -> y_] :> 
                  StringTake[ToString[(Hold@z)], {6, -2}] -> y, 2];
f[x] // InputForm

Out:

{"a" -> 1, "b" -> 2, "c" -> 3} 

Perhaps not very elegant, but seems to work.


This is a bit of an old question, but I think there's an answer that combines the virtues of both Andrew Moylan's answer and belisarius' answer. You really want to have lists of rules with HoldPattern on the left-hand side, instead of lists of rules that have Hold wrapped around the whole thing, so that you can actually use the rules without having to go through any sort of ReleaseHold process.

In[1]:= {a, b, c} = {1, 2, 3};

Unevaluated can also be helpful in constructing the sort of list you want:

In[2]:= x = Thread[HoldPattern /@ Unevaluated[{a, b, c}] -> Range[3]]
Out[2]= {HoldPattern[a] -> 1, HoldPattern[b] -> 2, HoldPattern[c] -> 3}

Now you can do what you want with rule replacement. It's a bit involved, but it's something I find myself doing over and over and over again. You may notice that this list of rules has almost exactly the form of a list of OwnValues or DownValues, so being able to manipulate it is very helpful. The trick is using HoldPattern and Verbatim in concert:

In[3]:= f[rules_] :=
         Replace[rules,
          HoldPattern[Verbatim[HoldPattern][s_Symbol] -> rhs_] :>
           With[{string = ToString[Unevaluated[s]]},
            string -> rhs], {1}]

The level spec on Replace is just there to make sure nothing unexpected happens if rhs is itself a rule or list of rules.

In[4]:= f[x] // InputForm
Out[4]= {"a" -> 1, "b" -> 2, "c" -> 3}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜