在scala中复制对象,但更改“子”以进行重写

时间:2010-09-15 11:47:20

标签: scala copy rewrite

kiama中,通用“dup”方法is defined复制Product个对象并将给定函数应用于Product的每个元素以支持重写Term s:

/**
 * General product duplication function.  Returns a product that applies
 * the same constructor as the product t, but with the given children            
 * instead of t's children.  Fails if a constructor cannot be found or
 * if one of the children is not of the appropriate type.
 */
private def dup (t : Product, children : Array[AnyRef]) : Product = {

    val ctor = (t.getClass.getConstructors())(0)
    try {
        val ret = ctor.newInstance (children : _*).asInstanceOf[Product]
        ret
                                                                                    } catch {
        case e : java.lang.ClassCastException =>
            error ("dup cast failed: " + t)
        case e : IllegalArgumentException =>
            error ("dup illegal arguments: " + ctor + " (" +
                   children.deep.mkString (",") + "), expects " +
                   ctor.getParameterTypes.length)
    }            
}

使用like this

private def childProduct (p : Product, i : Int, s : => Strategy) : Option[Term] = {
    val numchildren = p.productArity
    val ct = p.productElement (i-1)
    val children = new Array[AnyRef](numchildren)
    for (j <- 0 until numchildren)
       children (j) = makechild (p.productElement (j))
       s (ct) match {
                case Some (ti) =>
                    children (i-1) = makechild (ti)
                case None      =>
                    return None
           }
    val ret = dup (p, children)
    Some (ret)

这给出了一些使用限制。 我知道他们正在努力取代这种机制(Issue 2Issue 31),但我认为听听你们这样做会怎么样有趣呢?

例如,不会复制Positional var(或任何其他var!)的scala解析器组合器。事实上,一切都不是explict第一个构造函数的一部分(因而也是默认编译器生成的unapply方法)。

我一直在尝试提供某种特性或类似的东西,我可以添加到我的条件中,dup / childProduct / etc方法可以使用,但没有运气。 (我不知道如何使用案例类copy

2 个答案:

答案 0 :(得分:3)

我使用Kiama Rewriter模块的修改版本。它添加了一个Constructable特征,表示一个值可以deconstruct本身(使一个数组保持其成分/子元素)和reconstruct来自一组成分的新实例。当Kiama在其中一个方法Constructabledupchildall中遇到实现some的值时,它会避免使用反射代码,而是使用{ {1}}和deconstruct

除了将客户端代码从可以重写的类型中释放出construct的要求之外,还允许进行异构重写。换句话说,重写的类型不必与重写的值的具体类型完全相同。

缺点是客户端代码必须定义那些Productdeconstruct方法。

(最后并没有与你的问题密切相关,我添加了一个优化,如果转换子值(非原子值)的结果都等于原始值,则避免构建新值。我只添加了这个在处理construct的分支中。)

答案 1 :(得分:1)

我创建了一个小型GitHub存储库RSchulz/sbtr,其中包含我修改过的Kiama Rewriter.scala模块。在其中您将找到这些文件:

  • src/main/scala/rrs/sbtr/SBTR.scala - 我的“基于策略的术语重写”模块
  • src/main/scala/rrs/sbtr/RewriterFmt.alacs - 格式化我的样式约定后的原始代码
  • src/main/scala/rrs/sbtr/Rewriter-0.8.alacs - 稍微更新的0.8版本
  • src/main/scala/rrs/sbtr/Rewriter.alacs - 我开始的原始版本

区分前两个将公开我的修改,这些修改应该可以轻松地反向移植到当前的Kiama Rewriter.scala代码中。

Rewriter.scala来源的原始版本和0.8版本之间的主要区别是queryf的添加,我确实将其延续到SBTR。 0.8之后的变化尚未纳入。

后缀.alacs(向后拼写scala)用于防止这些文件被编译。据我所知,构建工具和IDE不能被指示忽略特定文件(至少不容易)。