如何在Scala中混入相同特质的不同类型实例?

3

我想检查不同的方式来扩展这个代码,然后在需要时混合这些功能扩展。

    // 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
  }

目前我遇到了一个错误,提示说:

"illegal inheritance; trait Test inherits different type instances of trait SubExpAlg: pack.SubExpAlg[pack.PPrint] and pack.SubExpAlg[pack.Eval]"

我该如何将类型Eval和PPint放在“帽子”下,以便被识别为同一家族的类型,而不是错误的解决方案?即使我可能会有两种类型成员之间的冲突继承,在这种情况下是否仍然可以保持兼容性?

编辑

我已经做出了更改,如下所示:

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类,并且通过引用这些类型来在两种方法之间进行导航。

1
当您在Test中写下lit(5)时,您实际上希望调用哪个方法? - dk14
@dk14,我在考虑一种递归调用test.add(lit(4).print, lit(5).print))的方法...就像这样。无论如何,我刚刚进行了编辑。 - Valerin
你为什么把问题中的所有代码都删除了?现在问题本身没有任何意义!“我如何扩展这段代码”是指哪段代码? - dk14
1个回答

6

让我们简化它:

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 内部的内容:
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
}

但是我建议选择一些默认方法,并从K继承Z,或者从Z继承K来为C#aa提供正常的默认实现。通常,在Scala中使用特质进行混入和多态性,因此您不能仅仅关闭其成员对外部世界的访问(由于Liskov-Substitution),即使您实际上不需要自动向超类型进行转换。有关详细信息,请参见相关问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接