最外层的访问策略究竟在Rascal中做了什么?

时间:2016-07-18 19:33:52

标签: visitor rascal

我编写了下面的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;
}

1 个答案:

答案 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访问代替最外层的代码替换你的代码?