gpt4 book ai didi

design-patterns - 具有相同参数化类型的 Scala mixin

转载 作者:行者123 更新时间:2023-12-04 07:00:27 25 4
gpt4 key购买 nike

我对 scala 非常陌生,并且正在寻求适应 scala 特定模式。
目标是将消息处理和消息生成分开。存在表示消息处理的基本协变参数化类型。具体实现可以通过常规的mixin组合,也可以通过底层协议(protocol)的混合实现。

要求是:

  • 尽可能简单地扩展
  • 类型安全以防止愚蠢的错误

  • 我提供了干净的示例代码(包含定义和使用):
    trait Protocol

    trait Handler [+proto <: Protocol] {
    def handle : PartialFunction[Protocol,Unit]
    /* can not name the actual protocol type since handler for a subtype also fully supports handling supertype
    besides any message extends other subtype ot the supertype since the scala use matching with case classes
    and these algebraic type realization is seemed excluded from strait scala type system
    */
    }

    /*
    ==============
    using scenario
    ==============
    */

    trait SumMsg extends Protocol
    case class Sum(op : Int) extends SumMsg
    case class Sub(op : Int) extends SumMsg

    trait ProdMsg extends Protocol
    case class Mul(op : Int) extends ProdMsg
    case class Diff(op : Int) extends ProdMsg {
    require (0 != op, "Division by zero is not permited")
    }

    /* stackable traites */
    trait NullHandler {
    def handle : PartialFunction[Protocol,Unit] = { case _ => {} }
    }

    trait SumHandler extends Handler [SumMsg] with NullHandler{
    var store : Int
    abstract override def handle : PartialFunction[Protocol,Unit] = ({
    case Sum(op) => { this.store += op}
    case Sub(op) => { this.store -= op}
    }: PartialFunction[Protocol,Unit]) orElse super.handle
    }

    trait MulHandler extends Handler [ProdMsg] with NullHandler{
    var store : Int
    abstract override def handle : PartialFunction[Protocol,Unit] = ({
    case Mul(op) => {this.store *= op}
    case Diff(op) => {this.store /= op}
    }: PartialFunction[Protocol,Unit]) orElse super.handle
    }

    /* concrete classes */
    class SumAccum (var store: Int) extends SumHandler

    class MulAccum (var store: Int) extends MulHandler

    class ArithmAccum (var store: Int) extends SumHandler with MulHandler

    /* producers */
    class ProduceSums (val accum : Handler [SumMsg]) {
    var state : Boolean = true
    def touch() = if (this.state)
    {
    this.state = false
    this.accum.handle(Sum(2))
    } else {
    this.state = true
    this.accum.handle(Sub(1))
    }
    }

    class ProduceProds (val accum : Handler [ProdMsg]) {
    var state : Boolean = true
    def touch() = if (this.state)
    {
    this.state = false
    this.accum.handle(Mul(2))
    } else {
    this.state = true
    this.accum.handle(Diff(2))
    }
    }

    /* tying together via cake pattern */
    trait ProtocolComp {
    type Proto <: Protocol
    }

    trait ProducerComp { this: ProtocolComp =>
    type ProducerT <: {def touch()}
    def getProducer(accum : Handler[Proto]) : ProducerT
    }

    trait HandlerComp { this: ProtocolComp =>
    type HandlerT <: Handler[Proto]
    def getHandler(store:Int) : HandlerT
    }

    trait AppComp extends ProtocolComp with ProducerComp with HandlerComp {
    val initStore = 1
    def test() {
    val handler = getHandler(initStore)
    val producer = getProducer(handler)
    producer.touch()
    }
    }

    /* different examples of compositions */

    /* correct usage */

    object One extends AppComp{
    override type Proto = SumMsg
    override type ProducerT = ProduceSums
    override type HandlerT = SumAccum
    override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
    override def getHandler(store : Int) = new SumAccum(store)
    }

    object Two extends AppComp{
    override type Proto = SumMsg
    override type ProducerT = ProduceSums
    override type HandlerT = ArithmAccum
    override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
    override def getHandler(store : Int) = new ArithmAccum(store)
    }

    object Three extends AppComp{
    override type Proto = SumMsg with ProdMsg
    override type ProducerT = ProduceSums
    override type HandlerT = ArithmAccum
    override def getProducer(accum : Handler[Proto]) = new ProduceSums(accum)
    override def getHandler(store : Int) = new ArithmAccum(store)
    }

    /* incorrect usage
    static type checking protects from some kind of logic errors
    */

    object Four extends AppComp{
    override type Proto = SumMsg
    override type ProducerT = ProduceProds
    override type HandlerT = SumAccum
    override def getProducer(accum : Handler[Proto]) = new ProduceProds(accum)
    override def getHandler(store : Int) = new SumAccum(store)
    }

    最后一个示例没有很好地键入并按预期给出错误:
    mixed.scala:140: error: type mismatch;
    found : Handler[Four.Proto]
    required: Handler[ProdMsg]
    override def getProducer(accum : Handler[Proto]) = new ProduceProds(accum)

    我已经构建了一个灵活的系统,具有简单的组合和扩展,但使用 scala 的案例类而不是 alegraic 类型尽可能类型安全

    我几乎实现了我的目标,但遇到了一个很大的 scala 错误功能:底层 jvm 的类型删除。我使用的结构对于 scala 是非法的,因为我希望参数化特征可以通过“with”子句进行扩展。

    编译器提示
    mixed.scala:53: error: illegal inheritance;
    class ArithmAccum inherits different type instances of trait Handler:
    Handler[ProdMsg] and Handler[SumMsg]
    class ArithmAccum (var store: Int) extends SumHandler with MulHandler

    我有什么选择?我无法使用我设计的模式,需要通过可用性找到同等的替代品。有人可以建议替代源代码解决方案吗?是否有 scala 插件(它们似乎存在于编译器)或另一种方法来将 scala 参数化类型的后端从 java 泛型更改为 c++ 之类的代码生成?

    最佳答案

    您的问题不是 JVM 的类型删除,而是 Scala 使用线性化来解决继承问题。

    从 Handler 中移除类型参数 [+proto <: Protocol]。无论如何,handle 方法不使用它。那么你的非法继承错误就会消失。

    关于design-patterns - 具有相同参数化类型的 Scala mixin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6637933/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com