我编写了下面的Rascal代码,该代码应该是从节点名称到节点的地图中构建一个树,从“top”映射的节点开始。它应该重复地将result
中具有字符串作为子节点的所有节点的子节点替换为节点nodeMap
映射到它们,直到没有任何更改(固定点)。
getNode
返回节点a map[str,node]
将其映射到的节点,或者键本身(如果它不作为地图中的键存在)。这工作正常,证明了这个问题底部的其他代码确实有效。但是,即使在非常小的输入上,下面的代码似乎仍然无法运行。
node nodeMapToNode(map[str, node] nodeMap) {
node result = nodeMap["top"];
return outermost visit(result) {
case node n: {
if ([*str children] := getChildren(n)) {
insert makeNode(getName(n), [getNode(child, nodeMap) | child <- children]);
}
}
}
}
以下代码可以正常工作,并在我预期的小输入上立即返回。然而,这正是我所理解的最外层访问应该从我从Rascal导师那里理解的内容。
有人可以向我解释这些代码片段之间的区别(除了它们的编写方式)以及我因此误解了outermost visit
的效果吗?此外,我想知道是否有更短和/或更好的方式编写此代码 - 使用最外层访问而不是手动编写修复点 - 确实存在。
node nodeMapToNode(map[str, node] nodeMap) {
node result = nodeMap["top"];
node lastResult;
do {
lastResult = result;
result = visit(lastResult) {
case node n: {
if ([*str children] := getChildren(n)) {
insert makeNode(getName(n),
[getNode(child, nodeMap) | child <- children]);
}
}
}
} while (result != lastResult);
return result;
}
答案 0 :(得分:2)
流氓导师的解释非常紧凑,但让我们从那里开始。
只要遍历改变结果值(计算一个固定点),重复自上而下的遍历。
以无赖的术语表示:
r = outermost visit(x) {
case str s => s + "."
when size(s) < 3
};
是语法糖:
r = x;
solve(r) {
r = top-down visit(r) {
case str s => s + "."
when size(s) < 3
};
}
我认为有两种常见的情况是最外层/最内层有意义:
关于你问题中的例子。另一个手动重写的outermost
实际上是innermost
。默认访问策略为bottom-up
。
一般来说,树的自下而上访问比自上而下更快。特别是当你重写它时,因为Rascal是不可变的,所以自下而上建立一个新的树更快。
那么,也许用innermost
访问代替最外层的代码替换你的代码?