gpt4 book ai didi

wolfram-mathematica - 何时在 Mathematica 中使用 Hold/ReleaseHold?

转载 作者:行者123 更新时间:2023-12-04 19:30:08 29 4
gpt4 key购买 nike

示例和背景(注意 Hold、ReleaseHold 的用法):
以下代码表示创建场景图对象(从 XML 文件)的静态工厂方法。 (输出)字段是 CScenegraph 的一个实例(一个 OO-System 类)。

 new[imp_]:= Module[{
ret,
type = "TG",
record ={{0,0,0},"Root TG"}
},
ret = MathNew[
"CScenegraph",
2,
MathNew["CTransformationgroup",1,{type,record},0,0,0,0,Null]];
ret@setTree[ret];
ret@getRoot[]@setColref[ret];
csp = loadClass["CSphere"];
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]];
ret
];
我的问题是关于以下内容:
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]];
在哪里
  addAschild 
将(一个列表)几何添加到(根)转换组并具有签名
  addAsChild[parent MathObject, child MathObject], or
addAsChild[parent MathObject, Children List{MathObject, ...}]
表示球体的 XML 元素如下所示:
  <sphere point='{0., 1., 3.}'
radius='1'
hue='0.55' />
如果我不使用 Hold[] , ReleaseHold[] 我最终会得到像这样的 objectdata
  {"GE", {"SP", {CScenegraph`point, CScenegraph`rad}}, {CScenegraph`hue}}
虽然我会预料到
  {"GE", {"SP", {{4., 3., -4.}, 3.}}, {0.45}}
(上面带有 Hold[]、ReleaseHold[] 的代码会产生正确的数据。)
问题
1. 为什么在这种情况下需要Hold? (事实上​​,是吗?有没有办法在没有 Hold[]、ReleaseHold[] 的情况下对此进行编码?)(我通过反复试验得到了正确的答案!不太明白为什么。)
2. 作为学习点:Hold/ReleaseHold 使用的原型(prototype)例子/案例是什么?
编辑:
列昂尼德的回答总结。更改此代码
  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];

最佳答案

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

由于您的代码示例不是独立的,因此很难确定发生了什么。要确定的一件事是,OO-System 使用上下文执行非平凡的操作,因为它使用上下文作为封装机制(这是有道理的)。通常情况下,RuleRuleDelayed在 r.h.s. 中注入(inject)匹配的表达式,因此尚不清楚这是如何发生的。这是一种可能的情况(您可以在笔记本中执行此操作):

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}}

发生的事情是,因为我们使用了 RuleXMLElement[...]->rhs , 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}]}

由于成语 XMLElement[...] :> rhs,这里的结果有所不同。用于实现 fn1 , 涉及 RuleDelayed这次。因此, f[{a,b}]直到 a 才被评估和 b被 l.h.s. 中的匹配数字取代。自从 f对于 2 个数字列表形式的参数没有规则,它被返回。

你的方法为什么用 Hold - ReleaseHold起作用的是,这阻止了 r.h.s. (函数 f 在我的示例中,以及对 new 的调用在您的原始示例中)从评估直到模式变量的值被替换到其中。作为旁注,您可能会发现向您的构造函数添加更好的错误检查很有用(如果 OO-System 允许),以便在运行时更好地诊断此类问题。

所以,底线:使用 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}

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

关于wolfram-mathematica - 何时在 Mathematica 中使用 Hold/ReleaseHold?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6706141/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com