Wolfram mathematica 在Mathematica中何时使用保持/释放保持?

Wolfram mathematica 在Mathematica中何时使用保持/释放保持?,wolfram-mathematica,Wolfram Mathematica,示例和背景(注意Hold、ReleaseHold的用法): 下面的代码表示一个静态工厂方法,用于(从XML文件)创建scenegraph对象。(output-)字段是CScenegraph(一个OO系统类)的实例 我的问题是: spheres = Cases[imp, XMLElement[\sphere\, _, __], Infinity]; codesp = Cases[spheres, XMLElement[\sphere\, {\point\ -> point_, \r

示例和背景(注意Hold、ReleaseHold的用法):

下面的代码表示一个静态工厂方法,用于(从XML文件)创建scenegraph对象。(output-)字段是CScenegraph(一个OO系统类)的实例

我的问题是:

spheres = Cases[imp, XMLElement[\sphere\, _, __], Infinity];
codesp = Cases[spheres, XMLElement[\sphere\, 
    {\point\ -> point_, \radius\ -> rad_, \"hue\" -> hue_}, {}] -> Hold[csp@new[ToExpression[point], ToExpression[rad], ToExpression[hue]]]];
ret@addAschild[ret@getRoot[],ReleaseHold[codesp]];
在哪里

向(根)transformationgroup添加(一组)几何图形,并具有签名

  addAsChild[parent MathObject, child MathObject], or
  addAsChild[parent MathObject, Children List{MathObject, ...}]
表示球体的XML元素如下所示:

  <sphere point='{0., 1., 3.}'
  radius='1'
  hue='0.55' />
而我本以为

  {"GE", {"SP", {{4., 3., -4.}, 3.}}, {0.45}}
(上面带有Hold[],ReleaseHold[]的代码生成正确的数据。)

问题 1.为什么在这种情况下需要保持?(事实上,是吗?有没有一种方法可以在没有Hold[],ReleaseHold[]的情况下编写此代码?)(我是通过反复试验才得到正确答案的!我真的不明白为什么。) 2.作为学习点:Hold/ReleaseHold使用的典型示例/案例是什么? 编辑: 列奥尼德回答的摘要。更改此代码

  codesp = Cases[spheres, XMLElement["sphere", 
{"point" -> point_, "radius" -> rad_, "hue" -> hue_}, {}] -> Hold[csp@new[ToExpression[point], ToExpression[rad], ToExpression[hue]]]];
  ret@addAschild[ret@getRoot[],ReleaseHold[codesp]];
致:


第一个问题的简短回答是,您可能应该使用
RuleDelayed
而不是
Rule
,然后您不需要
Hold
-
ReleaseHold

很难确定发生了什么,因为您的代码示例不是自包含的。可以肯定的是,OO系统对上下文执行非平凡的操作,因为它使用上下文作为封装机制(这是有意义的)。通常,
Rule
RuleDelayed
在r.h.s中注入匹配的表达式,因此不清楚这是如何发生的。以下是一种可能的情况(您可以在笔记本中执行此操作):

现在,

发生的情况是,由于我们在
XMLElement[…]->rhs
中使用了
Rule
,因此
r.h.s.
在替换发生之前进行求值-在本例中,函数
f
进行求值。现在,

In[78]:= Test`fn1[{XMLElement[{"a" -> 1, "b" -> 2}, {}, {}], 
      {"a" ->3, "b" -> 4}, {"a" -> 5, "b" -> 6}}]

Out[78]= {Test`f[{1, 2}]}
这里的结果不同,因为在
fn1
的实现中使用了习惯用法
xmlement[…]:>rhs
,这一次涉及
RuleDelayed
。因此,
f[{a,b}]
a
b
被l.h.s.中的匹配数字替换之前没有进行计算,并且由于
f
没有2个数字的列表形式的参数规则,因此返回它

使用
Hold
-
ReleaseHold
的方法之所以有效,是因为这阻止了r.h.s.(在我的示例中是函数
f
,在原始函数中是调用
new
)进行求值,直到模式变量的值被替换到其中。作为旁注,您可能会发现在构造函数中添加更好的错误检查很有用(如果OO系统允许的话),这样在运行时就可以更好地诊断此类问题

因此,底线是:使用
RuleDelayed
,而不是
Rule


要回答第二个问题,当您希望在允许对保留的代码进行计算之前对其进行操作时,
ReleaseHold
-
Hold
组合通常很有用。例如:

In[82]:= 
{a,b,c}={1,2,3};
ReleaseHold[Replace[Hold[{a,b,c}],s_Symbol:>Print[s^2],{2}]]

During evaluation of In[82]:= 1
During evaluation of In[82]:= 4
During evaluation of In[82]:= 9

Out[83]= {Null,Null,Null}

人们可能会想出更明智的例子。这对于代码生成之类的事情特别有用——可以找到一个不那么简单的例子。正如我已经提到的,手头的具体案例并不真正属于
Hold
-
ReleaseHold
有益的案例类别,它们只是一种解决方法,在使用延迟规则时并不真正需要。

Leonid(这是胚胎代码,仍然需要大量的工作,但我必须从一些东西开始。)RuleDelayed对我来说是相当新的,我会仔细阅读,毫无疑问你是对的。添加到Expression是在我的试用/错误会话中尝试修复它。我将尝试在没有它的情况下运行。-再次感谢你的帮助。@ndroock1我发现自己使用
RuleDelayed
的频率要比
Rule
高出很多,原因正是我在上面描述的原因。一般来说,它更安全。我在这里介绍了这些主题:,尽管是在一个相当初级的层次上。通过阅读过去,你可以找到许多涉及它的例子,因此Mathematica questons:
RuleDelayed
在mma编程中确实无处不在。阅读它是一个非常好的主意,因为学习它的用法是必不可少的用于创建非平凡的mma程序。Leonid,一定会阅读此主题。-我尝试过,但在这一阶段不能错过表达(在球体构造函数中,我添加了翻译向量,因此它必须包含数字数据。)无论如何,在以后的代码清理中可能会出现这种情况。@ndroock1您对
表达的看法是正确的
-我的错。它们只是在错误的方法中无效(没有
保持
-
释放保持
),其中符号未被值替换。由于值是字符串,因此应将其解析为数字。我将编辑我的答案。@_Leonid我已总结了您在下面问题的第1部分中的答案。
  codesp = Cases[spheres, XMLElement["sphere", 
{"point" -> point_, "radius" -> rad_, "hue" -> hue_}, {}] -> Hold[csp@new[ToExpression[point], ToExpression[rad], ToExpression[hue]]]];
  ret@addAschild[ret@getRoot[],ReleaseHold[codesp]];
  codesp = Cases[spheres, XMLElement["sphere", 
{"point" -> point_, "radius" -> rad_, "hue" -> hue_}, {}] :> csp@new[ToExpression[point], ToExpression[rad], ToExpression[hue]]];
  ret@addAschild[ret@getRoot[],codesp];
BeginPackage["Test`"]
f[{a_Symbol, b_Symbol}] := {c, d};
fn[input_] :=  Cases[input, XMLElement[{"a" -> a_, "b" -> b_}, {}, {}] -> f[{a, b}]];
fn1[input_] := Cases[input, XMLElement[{"a" -> a_, "b" -> b_}, {}, {}] :> f[{a, b}]];
EndPackage[];
$ContextPath = DeleteCases[$ContextPath, "Test`"]
In[71]:= Test`fn[{XMLElement[{"a"->1,"b"->2},{},{}],{"a"->3,"b"->4},{"a"->5,"b"->6}}]
Out[71]= {{Test`c,Test`d}}
In[78]:= Test`fn1[{XMLElement[{"a" -> 1, "b" -> 2}, {}, {}], 
      {"a" ->3, "b" -> 4}, {"a" -> 5, "b" -> 6}}]

Out[78]= {Test`f[{1, 2}]}
In[82]:= 
{a,b,c}={1,2,3};
ReleaseHold[Replace[Hold[{a,b,c}],s_Symbol:>Print[s^2],{2}]]

During evaluation of In[82]:= 1
During evaluation of In[82]:= 4
During evaluation of In[82]:= 9

Out[83]= {Null,Null,Null}