如何在Scala中混合相同特征的不同类型实例? [英] How to mixin different type instances of same trait in Scala?

查看:45
本文介绍了如何在Scala中混合相同特征的不同类型实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以不同的方式检查如何扩展此代码,然后在最后根据需要混合这些功能扩展.

I wanted to check different way how I can extend this code and then to mix this extensions of functionalities at the end as they are needed.

    // Initial object algebra interface for expressions: integers and addition
    trait ExpAlg[E] {
        def lit(x : Int) : E 
        def add(e1 : E, e2 : E) : E
    }

    // An object algebra implementing that interface (evaluation)

    // The evaluation interface
    trait Eval {
        def eval() : Int
    }

    // The object algebra
    trait EvalExpAlg extends ExpAlg[Eval] {
        def lit(x : Int) = new Eval() {
            def eval() = x
        }

        def add(e1 : Eval, e2 : Eval) = new Eval() {
            def eval() = e1.eval() + e2.eval()
        }
    }

    // Evolution 1: Adding subtraction
    trait SubExpAlg[E] extends ExpAlg[E] {
        def sub(e1 : E, e2 : E) : E
    }

    // Updating evaluation:
    trait EvalSubExpAlg extends EvalExpAlg with SubExpAlg[Eval] {
        def sub(e1 : Eval, e2 : Eval) = new Eval() {
            def eval() = e1.eval() - e2.eval()
        }
    }

    // Evolution 2: Adding pretty printing
    trait PPrint {
        def print() : String
    }


    trait PrintExpAlg extends ExpAlg[PPrint] {
      def lit(x: Int) = new PPrint() {
        def print() = x.toString()
      }
      def add(e1: PPrint, e2: PPrint) = new PPrint() {
        def print() = e1.print() + "+" + e2.print()
      }
    }

    trait PrintSubExpAlg extends PrintExpAlg with SubExpAlg[PPrint] {
      def sub(e1: PPrint, e2: PPrint) = new PPrint() {
        def print() = e1.print() + "-" + e2.print()
      }
    }

object OA extends App {

trait Test extends EvalSubExpAlg with PrintSubExpAlg //error
  }

目前我收到一条错误消息:"非法继承;trait Test 继承了 trait SubExpAlg 的不同类型实例:pack.SubExpAlg[pack.PPrint] 和 pack.SubExpAlg[pack.Eval]"

Currently I am getting an error saying that : "illegal inheritance; trait Test inherits different type instances of trait SubExpAlg: pack.SubExpAlg[pack.PPrint] and pack.SubExpAlg[pack.Eval]"

如何将两种类型的 Eval 和 PPint 放在帽子"下以被识别为来自同一家族的类型,或者不是正确的解决方案,而我仍然可能在两种类型的成员之间存在冲突的继承?

How I can put two types Eval and PPint under a "hat" to be recognized as types from the same family or is not a right solution while still I may have conflicting inheritance between members of two types then?

我将其更改如下:类操作

I changed it like in the following: class Operations

// Initial object algebra interface for expressions: integers and addition
    trait ExpAlg {
        type Opr <: Operations
        def lit(x : Int) : Opr 
        def add(e1 : Opr, e2 : Opr) : Opr
    }

    // An object algebra implementing that interface (evaluation)

    // The evaluation interface
    trait Eval extends Operations {
        def eval() : Int
    }

    // The object algebra
    trait EvalExpAlg extends ExpAlg {
        type Opr = Eval
        def lit(x : Int) = new Eval() {
            def eval() = x
        }

        def add(e1 : Eval, e2 : Eval) = new Eval() {
            def eval() = e1.eval() + e2.eval()
        }
    }

    // Evolution 1: Adding subtraction
    trait SubExpAlg extends ExpAlg {
        def sub(e1 : Opr, e2 : Opr) : Opr
    }

    // Updating evaluation:
    trait EvalSubExpAlg extends EvalExpAlg with SubExpAlg {
        def sub(e1 : Eval, e2 : Eval) = new Eval() {
            def eval() = e1.eval() - e2.eval()
        }
    }

    // Evolution 2: Adding pretty printing
    trait PPrint extends Operations {
        def print() : String
    }


    trait PrintExpAlg extends ExpAlg {
      type Opr = PPrint
      def lit(x: Int) = new PPrint() {
        def print() = x.toString()
      }
      def add(e1: PPrint, e2: PPrint) = new PPrint() {
        def print() = e1.print() + "+" + e2.print()
      }
    }

    trait PrintSubExpAlg extends PrintExpAlg with SubExpAlg {
      def sub(e1: PPrint, e2: PPrint) = new PPrint() {
        def print() = e1.print() + "-" + e2.print()
      }
    }

object OA extends App {

class Test extends EvalSubExpAlg
class Test2 extends PrintSubExpAlg

val evaluate = new Test
val print = new Test2
val l1 = evaluate.lit(5)
val l2 = evaluate.lit(4)
val add1 = evaluate.add(l1, l2).eval()
val print1 = print.add(print.lit(5), print.lit(4)).print()

println(print1)
println(add1)
}

我唯一要问的可能是只使用一个 Test 类并在两种类型的方法之间导航(通过引用这些类型).

The only thing that I was asking probably was to use only one Test class and to navigate between methods of both types (through referencing those types).

推荐答案

让我们简化一下:

trait Z {val a = 5}
trait K {val a = 6}
trait A[T] { def aa: T}
trait A1 extends A[Z] { def aa = new Z{}}
trait A2 extends A[K] { def aa = new K{}}
scala> class C extends A1 with A2
<console>:12: error: illegal inheritance;
 class C inherits different type instances of trait A:
A[K] and A[Z]

那么,当您执行 (new C).aa 时,您希望被调用什么?如果您实际上并不关心并且只想访问 C 中的那些:

So, what do you expect to be called, when you do (new C).aa? If you actually don't care and just want to access those inside C:

trait A {type T; protected def aa: T}
trait A1 extends A {type T >: Z; protected def aa = new Z{}}
trait A2 extends A {type T >: K; protected def aa = new K{}}

scala> class C extends A1 with A2 {
   override type T = Any
   override protected def aa = ???
   def bbb:Z = super[A1].aa
   def zzz:K = super[A2].aa
}

但我建议选择一些默认方法并将 ZKKZ 继承到为 C#aa 提供正常的默认实现.通常,这里的问题是 scala 中的 trait 既适用于 mixin 又适用于多态性,因此您不能只为外部世界关闭它们的成员(由于 Liskov-Substitution),即使您实际上并不需要自动转换为超类型.详情请参阅相关问题.

But I would recommend to choose some default method and inherit Z from K or K from Z to provide normal default implementation for C#aa. Generally, the problem here is that traits in scala are intended for both mixins and polymorphism, so you can't just close their members for outside world (due to Liskov-Substitution), even if you don't actually need automatic cast to the supertype. See related question for details.

这篇关于如何在Scala中混合相同特征的不同类型实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆