代码之家  ›  专栏  ›  技术社区  ›  svrist

仅部分匹配的结构上的映射

  •  1
  • svrist  · 技术社区  · 16 年前

    我有一个抽象类和case类的树形结构,表示一个小语言的抽象语法树。

    对于顶级抽象类,我实现了一个方法 map :

    abstract class AST {
    ...
      def map(f: (AST => AST)): AST = {
         val b1 =  this match {
          case s: STRUCTURAL => s.smap(f) // structural node for example IF(expr,truebranch,falsebranch)
          case _ => this // leaf, // leaf, like ASSIGN(x,2)
        }
        f(b1)
      }
    ...
    

    SMAP的定义如下:

     override def smap(f: AST => AST) = {
        this.copy(trueb = trueb.map(f), falseb = falseb.map(f))
      }
    

    现在我在编写不同的“转换”来插入、删除和更改AST中的节点。

    例如,从块中删除相邻的nop节点:

    def handle_list(l:List[AST]) = l match {
      case (NOP::NOP::tl) => handle_list(tl)
      case h::tl => h::handle_list(tl)
      case Nil => Nil
    }
    
    ast.map {
      case BLOCK(listofstatements) => handle_list(listofstatements)
    }
    

    如果我这样写,我最终会 MatchError 我可以把上面的地图改成:

    ast.map {
      case BLOCK(listofstatements) => handle_list(listofstatements)
      case a => a
    }
    

    我应该和这些人一起生活吗? case a => a 或者我可以提高我的 地图 方法(或其他部分)?

    2 回复  |  直到 16 年前
        1
  •  4
  •   Alexey Romanov    16 年前

    使争论 map PartialFunction :

    def map(f: PartialFunction[AST, AST]): AST = {
      val idAST: PartialFunction[AST, AST] = {case a => a}
      val g = f.orElse(idAST)
    
      val b1 =  this match {
        case s: STRUCTURAL => s.smap(g)
        case _ => this
      }
      g(b1)
    }
    
        2
  •  4
  •   Randall Schulz    16 年前

    如果树转换不仅仅是项目的一个小方面,我强烈建议您使用 Kiama 的重写器模块来实现它们。它实现了战略驱动的转型。它有一套非常丰富的策略和策略组合器,允许遍历逻辑(在大多数情况下,可以从所提供的策略和组合器“现成”的)与(本地)转换(当然,这些转换是特定于您的AST和您提供的)完全分离。

    推荐文章