Skip to content

Instantly share code, notes, and snippets.

@gakuzzzz
Last active January 6, 2016 09:45
Show Gist options
  • Save gakuzzzz/348ebcddcf9b2989b2d6 to your computer and use it in GitHub Desktop.
Save gakuzzzz/348ebcddcf9b2989b2d6 to your computer and use it in GitHub Desktop.
Visitor の factory
public interface TreeVisitor<T> {
  T visitLeaf();
  T visitNode(Node node);
}

こういうVisitorなら以下の様なファクトリがあると便利かなと思ったけど

public interface TreeVisitor<T> {
  T visitLeaf();
  T visitNode(Node node);

  static <TT> TreeVisitor<TT> of(Supplier<? extends T> forLeaf, Function<? super Node, ? extends T> forNode) {
      return new TreeVisitor<TT>() {
         public TT visitLeaf() {
             return forLeaf.get();
         }
         public TT visitNode(Node node) {
             return forNode.apply(node);
         }
      }
  }
}

Composite パターンのような構造を走査する場合、this でVisitor自身を参照できなくなるのであんまり便利にならないですね。

Enum に対する Visitor とかなら便利かも位

Visitor を受け取れるようにしてみる

public interface TreeVisitor<T> {
  T visitLeaf();
  T visitNode(Node node);

  static <TT> TreeVisitor<TT> of(Function<? super TreeVisitor<? extends TT>, ? extends T> forLeaf, BiFunction<? super Node, ? super TreeVisitor<? extends TT>, ? extends TT> forNode) {
      return new TreeVisitor<TT>() {
         public TT visitLeaf() {
             return forLeaf.apply(this);
         }
         public TT visitNode(Node node) {
             return forNode.apply(node, this);
         }
      }
  }
}

とするとこの辺の例も以下の様にかける

Doc doc = tree.accept(TreeVisitor.of<Doc>(
         self  -> Doc.text("Leaf"),
  (node, self) -> {
    Doc lhsDoc = node.lhs.accept(self);
    Doc rhsDoc = node.rhs.accept(self);
    Doc inner = lhsDoc.concat(Doc.line()).concat(rhsDoc);
    Doc ret = Doc.bracket("(Node " + node.value, inner, ")");
    return ret;
});
System.out.println(doc.layout());

すっきり。

でも数が増えると意味わからないので名前付きメソッド呼び出し欲しい。

// 妄想。コンパイル通らない
Doc doc = tree.accept(TreeVisitor.of<Doc>(
  forLeaf =        self  -> Doc.text("Leaf"),
  forNode = (node, self) -> {
    Doc lhsDoc = node.lhs.accept(self);
    Doc rhsDoc = node.rhs.accept(self);
    Doc inner = lhsDoc.concat(Doc.line()).concat(rhsDoc);
    Doc ret = Doc.bracket("(Node " + node.value, inner, ")");
    return ret;
});
System.out.println(doc.layout());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment