加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

驯服Scala类型系统

发布时间:2020-12-16 09:21:13 所属栏目:安全 来源:网络整理
导读:我似乎不了解Scala类型系统.我试图实现 两个基本特征和一系列算法与它们一起工作的特征. 下面我做错了什么? 移动的基本特征状态;这些被简化为仅包括 暴露问题的方法. trait Movetrait State[M : Move] { def moves: List[M] def successor(m: M): State[M]}
我似乎不了解Scala类型系统.我试图实现
两个基本特征和一系列算法与它们一起工作的特征.
下面我做错了什么?

移动的基本特征状态;这些被简化为仅包括
暴露问题的方法.

trait Move
trait State[M <: Move] {
    def moves: List[M]
    def successor(m: M): State[M]
}

以下是使用上述算法的系列的特征.
我不知道这是对的!
可能有一些M / -S的东西涉及…

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
建议.这解决了这个问题,就像我已经说过的那样
简化了一点点. MyAlgorithm.bestMove()方法必须是
允许使用s.successor(m)的输出调用自身,如下所示:

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会给我这个能力.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读