驯服Scala类型系统
我似乎不了解Scala类型系统.我试图实现
两个基本特征和一系列算法与它们一起工作的特征. 下面我做错了什么? 移动的基本特征状态;这些被简化为仅包括 trait Move trait State[M <: Move] { def moves: List[M] def successor(m: M): State[M] } 以下是使用上述算法的系列的特征. trait Algorithm { def bestMove[M <: Move,S <: State[M]](s: S): M } 具体举动和状态: case class MyMove(x: Int) extends Move class MyState(val s: Map[MyMove,Int]) extends State[MyMove] { def moves = MyMove(1) :: MyMove(2) :: Nil def successor(p: MyMove) = new MyState(s.updated(p,1)) } 我在下面非常摇摇欲坠的地面,但编译器似乎接受了… object MyAlgorithm extends Algorithm { def bestMove(s: State[Move]) = s.moves.head } 到目前为止还没有编译错误;但是,当我尝试将所有零件放在一起时,它们会显现出来: object Main extends App { val s = new MyState(Map()) val m = MyAlgorithm.bestMove(s) println(m) } 上面提到这个错误: error: overloaded method value bestMove with alternatives: (s: State[Move])Move <and> [M <: Move,S <: State[M]](s: S)M cannot be applied to (MyState) val m = MyAlgorithm.bestMove(s) ^ 更新:我将Algorithm trait改为使用抽象类型成员,as trait Algorithm { type M <: Move type S <: State[M] def bestMove(s: S): M } trait MyAlgorithm extends Algorithm { def score(s: S): Int = s.moves.size def bestMove(s: S): M = { val groups = s.moves.groupBy(m => score(s.successor(m))) val max = groups.keys.max groups(max).head } } 以上给出了2个错误: Foo.scala:38: error: type mismatch; found : State[MyAlgorithm.this.M] required: MyAlgorithm.this.S val groups = s.moves.groupBy(m => score(s.successor(m))) ^ Foo.scala:39: error: diverging implicit expansion for type Ordering[B] starting with method Tuple9 in object Ordering val max = groups.keys.max ^ 我必须采取一种方法,使用特征的特征,即蛋糕模式,以使这项工作? (我只是在这里猜猜,我还是很困惑) 解决方法
更新代码.
编译器非常公平的投诉.算法使用状态的一个子类表示,状态后继可以返回状态[M]的任何其他子类 您可以声明IntegerOne类 trait Abstract[T] class IntegerOne extends Abstract[Int] 但是编译器并不知道AbstractOne [Int]的所有实例都是IntegerOne.它假设可能还有另一个类也实现Abstract [Int] class IntegerTwo extends Abstract[Int] 您可以尝试使用从Abstract [Int]转换为IntegerOne的隐式转换,但traits没有隐式视图边界,因为它们根本没有值参数. 解决方案0 所以你可以重写你的算法trait作为抽象类并使用隐式转换: abstract class MyAlgorithm[MT <: Move,ST <: State[MT]] (implicit val toSM : State[MT] => ST) extends Algorithm { override type M = MT // finalize types,no further subtyping allowed override type S = ST // finalize types,no further subtyping allowed def score(s : S) : Int = s.moves.size override def bestMove(s : S) : M = { val groups = s.moves.groupBy( m => score(toSM ( s.successor(m)) ) ) val max = groups.keys.max groups(max).head } } implicit def toMyState(state : State[MyMove]) : MyState = state.asInstanceOf[MyState] object ConcreteAlgorithm extends MyAlgorithm[MyMove,MyState] object Main extends App { val s = new MyState(Map()) val m = ConcreteAlgorithm.bestMove(s) println(m) } 这个解决方案有两个缺点 >使用asInstanceOf隐式转换 您可能会首先扑灭进一步类型绑定的费用. 解决方案1 使用算法作为唯一类型的参数化源,并相应地重写类型结构 trait State[A <: Algorithm] { _:A#S => def moves : List[A#M] def successor(m : A#M): A#S } trait Algorithm{ type M <: Move type S <: State[this.type] def bestMove(s : S) : M } 在这种情况下,您可以使用MyAlgorithm而不重写 trait MyAlgorithm extends Algorithm { def score(s : S) : Int = s.moves.size override def bestMove(s : S) : M = { val groups = s.moves.groupBy(m => score(s.successor(m))) val max = groups.keys.max groups(max).head } } 使用它: class MyState(val s : Map[MyMove,Int]) extends State[ConcreteAlgorithm.type] { def moves = MyMove(1) :: MyMove(2) :: Nil def successor(p : MyMove) = new MyState(s.updated(p,1)) } object ConcreteAlgorithm extends MyAlgorithm { override type M = MyMove override type S = MyState } object Main extends App { val s = new MyState(Map()) val m = ConcreteAlgorithm.bestMove(s) println(m) } 查看更多抽象和复杂的用法示例:Scala: Abstract Types vs Generics 解决方案2 还有一个简单的解决方案,你的问题,但我怀疑它可以解决你的问题.在更复杂的用例中,您将再次陷入类型不一致之处. 只需让MyState.successor返回this.type而不是State [M] trait State[M <: Move] { def moves : List[M] def successor(m : M): this.type } final class MyState(val s : Map[MyMove,Int]) extends State[MyMove] { def moves = MyMove(1) :: MyMove(2) :: Nil def successor(p : MyMove) = (new MyState(s.updated(p,1))).asInstanceOf[this.type] } 其他事情没有改变 trait Algorithm{ type M <: Move type S <: State[M] def bestMove(s : S) : M } trait MyAlgorithm extends Algorithm { def score(s : S) : Int = s.moves.size override def bestMove(s : S) : M = { val groups = s.moves.groupBy(m => score(s.successor(m))) val max = groups.keys.max groups(max).head } } object ConcreteAlgorithm extends MyAlgorithm { override type M = MyMove override type S = MyState } object Main extends App { val s = new MyState(Map()) val m = ConcreteAlgorithm.bestMove(s) println(m) } 注意MyState类的最终修饰符.它确保转换asInstanceOf [this.type]是正确的. Scala编译器可以自己计算最终类始终是this.type,但它仍然有一些缺陷. 解决方案3 没有必要使用自定义状态绑定算法.只要算法不使用特定的状态函数,它可以被写得更简单,没有类型的边界练习. trait Algorithm{ type M <: Move def bestMove(s : State[M]) : M } trait MyAlgorithm extends Algorithm { def score(s : State[M]) : Int = s.moves.size override def bestMove(s : State[M]) : M = { val groups = s.moves.groupBy(m => score(s.successor(m))) val max = groups.keys.max groups(max).head } } 这个简单的例子不是快速地出现在我的脑海里,因为我认为绑定到不同的国家是强制性的.但有时只有部分系统真的应该被明确地参数化,并且可以避免额外的复杂性 结论 讨论的问题反映了我经常出现的一系列问题. 有两个竞争的目的不应该相互排斥,而是在scala中这样做. >可扩展性 首先意味着你可以建立复杂的系统,实现一些基本的实现,并能逐一替换它的部分来实现更复杂的实现. 第二个允许你定义非常抽象的系统,可以用于不同的情况. Scala开发人员非常具有挑战性的任务,即创建可以兼容功能和面向对象的语言类型系统,同时受限于jvm实现核心,具有诸如类型擦除之类的巨大缺陷.给予用户的Co / Contra-variance类型注释不足以表示复杂系统中的类型关系 每次遇到可扩展性的两难困境时,我都有艰难的时刻决定哪一个权衡要接受. 我不想使用设计模式,而是用目标语言来声明它.我希望有一天这个scala会给我这个能力. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |