为递归和嵌套类型结构定义隐式转换

时间:2013-11-23 06:08:44

标签: scala recursion nested-class implicits

我定义了以下类,PositionSpace,它有嵌套类Position和SubPositionSpace。 SubPositionSpace本身既是Position又是PositionSpace(因此它也是一个定义了自己位置的位置)。我已经定义了一个包装类SubPosition,因此任何类型为x.SubPositionSpace#Position的对象(对于任何作为PositionSpace的对象x)都可以用作x.Position类型的对象。但是,我想隐含这种转换,这就是我被困住的地方。从逻辑上讲,它应该是可能的。但是,我无法弄清楚在何处或如何定义转换,以便编译器找到它,并且它让我头疼。

以下是我的代码。请注意,我已将测试用例添加到底部。

class PositionSpace { positionSpace =>

  //snip

  trait Position extends Ordered[Position] {
    //snip
  }

  class SubPositionSpace() extends PositionSpace with Position { subPositionSpace =>

    //snip

    //wrapper class to treat a x.SubPositionSpace#Position as a x.Position for some x : PositionSpace
    //want to make this conversion implicit!!!
    class SubPosition(private val subPositionIndex : subPositionSpace.Position) extends positionSpace.Position {
      //snip
    }
  }

  def append() = new Position{
    //snip
  }

  def appendSubSpace() = new SubPositionSpace()
}

object TestCases {
  val positionSpace = new PositionSpace()
  val subSpace = positionSpace.appendSubSpace()
  val subSpacePosition = subSpace.append()
  //Does not compile, needs an implicit conversion:
  val subSpacePositionAsPosition : positionSpace.Position = subSpacePosition
  val subSubSpace = subSpace.appendSubSpace()
  //Does not compile, needs an implicit conversion:
  val subSubSpacePositionAsPosition : positionSpace.Position = subSubSpace
}

我遇到的路障

与路径相关的类型

部分问题似乎是此转换涉及路径相关类型,其中输入类型和输出类型使用相同的路径。但是,没有语法来编写具有类型x.Position => y.Position where y : PositionSpace and x : y.SubPositionSpace.的签名的方法。通过添加额外的参数来传递路径(如下所示)可以很容易地解决问题,但是您无法添加其他参数隐式转换方法(如果您希望它们可以这样使用)。

//Too many arguments, won't be used by compiler for implicit conversions
implicit def promotePosition(y : PositionSpace, x : y.PositionSpace, x.Position) : y.Position = ...

2 个答案:

答案 0 :(得分:1)

这是我想出的部分答案并开始工作。基本上,您创建一个空特征SubPositionSpacePosition,它应用于所有2级位置。然后,您可以为SubPositionSpacePosition定义一个定义隐式转换的伴随对象。您只能将leve-2位置的转换定义为level-1位置。除此之外的任何事情,你都遇到了我在问题中概述的障碍。

import scala.language.implicitConversions

class PositionSpace { positionSpace =>

  trait Position extends Ordered[Position] {

  }

  trait SubPositionSpace extends PositionSpace with Position { subPositionSpace =>
    trait SubPositionSpacePosition extends subPositionSpace.Position {
    }

    def append() = new Position with SubPositionSpacePosition { }

    def appendSubSpace() = new SubPositionSpace with SubPositionSpacePosition { }

    class SubPosition(private val subPositionIndex : subPositionSpace.Position) extends positionSpace.Position {
    }

    object SubPositionSpacePosition {
      implicit def promoteSubPositionSpacePosition(subPositionSpacePosition : SubPositionSpacePosition) : positionSpace.Position =
        new SubPosition(subPositionSpacePosition)
    }
  }

  def append() = new Position { }

  def appendSubSpace() = new SubPositionSpace { }
}

object TestCases {
  val positionSpace = new PositionSpace()
  val subSpace = positionSpace.appendSubSpace()
  val subSpacePosition = subSpace.append()
  val subSpacePositionAsPosition : positionSpace.Position = subSpacePosition
  val subSubSpace = subSpace.appendSubSpace()
  val subSubSpacePosition = subSubSpace.append()
  //this still fails to build!!!
  val subSubSpacePositionAsPosition : positionSpace.Position = subSubSpacePosition
}

答案 1 :(得分:0)

我认为你不想在这里进行隐式转换 - 仅仅为类型系统提供跟踪路径依赖类型所需的信息会更加清晰。实现此目的的一种方法是抽象出将类型联系在一起的骨架:

trait PSpace { pSpace =>
  type P
  type Sub <: P with PSpace {
    type P = pSpace.P
    type Sub = pSpace.Sub
  }

  def append(): P
  def appendSubSpace(): Sub
}

您也可以使用类型参数,但我猜测类型成员会更好用于您的用例。然后你提供你的实现:

class PositionSpace { positionSpace =>
  type P = Position
  type Sub = SubPositionSpace

  trait Position

  class SubPositionSpace() extends PSpace with Position {
    type P = positionSpace.P
    type Sub = positionSpace.Sub

    class SubPosition(private val subPositionIndex: P) extends P

    def append() = new Position {}
    def appendSubSpace() = new SubPositionSpace()
  }

  def append() = new Position {}
  def appendSubSpace() = new SubPositionSpace()
}

现在,测试代码的所有行都可以正常编译。