scala - 类型类和依赖类型

标签 scala typeclass implicit

首先,我不知道如何正确标记我的问题。这也可能是我没有找到有用资源的原因。任何提示都非常感谢。

trait Context[T]
{
    self =>

    trait Rule
    {
        def apply( value: T ): Boolean
    }

    implicit class RichRule[A <: Rule]( a: A )
    {
        def and[B <: Rule]( b: B ): and[A, B] = self.and( a, b )
        def or[B <: Rule]( b: B ): or[A, B] = self.or( a, b )
    }

    sealed trait Group[A <: Rule, B <: Rule] extends Rule
    {
        def a: A

        def b: B

        override def apply( value: T ) = ???
    }

    case class and[A <: Rule, B <: Rule]( a: A, b: B ) extends Group[A, B]
    case class or[A <: Rule, B <: Rule]( a: A, b: B ) extends Group[A, B]
}

鉴于上述代码,我现在可以定义和链接 Rules以这种方式:
new Context[String]
{
    class MyRule extends Rule
    {
        override def apply( value: String ) = true
    }

    case class A() extends MyRule
    case class B() extends MyRule

    val x1: A and B or A = A() and B() or A()
}

这按我的意图工作,但现在是棘手的部分。我想引入一个类型类 Combination这解释了如何加入两个规则。
trait Combination[-A <: Rule, -B <: Rule]
{
    type Result <: Rule

    def combine( a: A, b: B ): Result
}
trait AndCombination[-A <: Rule, -B <: Rule] extends Combination[A, B]
trait OrCombination[-A <: Rule, -B <: Rule] extends Combination[A, B]

这个类型类现在应该与操作符一起传递。
implicit class RichRule[A <: Rule]( a: A )
{
    def and[B <: Rule]( b: B )( implicit c: AndCombination[A, B] ): and[A, B] = ???
    def or[B <: Rule]( b: B )( implicit c: OrCombination[A, B] ): or[A, B] = self.or( a, b )
}

经过一些调整后仍然有效。
implicit val c1 = new Combination[MyRule, MyRule]
{
    type Result = MyRule

    def combine( a: A, b: B ): MyRule = a
}

val x: A and B = A() and B()

但如果事情变得更复杂,事情就会分崩离析。
A() and B() and A()

将引发隐式缺失错误:Combination[and[A, B], A]不见了。但我希望它使用 and[A, B] 的隐式组合的结果( type Result = MyRule )它已经知道如何处理( Combination[and[A, B]#Result, A] )。

保留组合规则的类型信息对我来说很重要val x: A and B or A ,将它们折叠在一起形成最终结果类型很容易,但不是我想要的。

这是我能得到的最接近的结果,但是编译失败。
trait Context[T]
{
    self =>

    trait Rule

    trait Value extends Rule

    trait Group[A <: Rule, B <: Rule] extends Rule
    {
        def a: A

        def b: B

        implicit val resolver: Resolver[_ <: Group[A, B]]
    }

    case class and[A <: Rule, B <: Rule]( a: A, b: B )( implicit val resolver: Resolver[and[A, B]] ) extends Group[A, B]

    implicit class RichRule[A <: Rule]( a: A )
    {
        def and[B <: Rule]( b: B )( implicit resolver: Resolver[and[A, B]] ) = self.and[A, B]( a, b )
    }

    trait Resolver[-A <: Rule]
    {
        type R <: Value

        def resolve( a: A ): R
    }
}

object O extends Context[String]
{
    implicit val c1 = new Resolver[A and A]
    {
        override type R = A

        override def resolve( a: O.and[A, A] ) = ???
    }

    implicit def c2[A <: Value, B <: Value, C <: Value]( implicit r1: Resolver[A and B] ) = new Resolver[A and B and C]
    {
        override type R = C

        override def resolve( a: A and B and C ): C =
        {
            val x: r1.R = r1.resolve( a.a )
            new c2( x )
            ???
        }
    }

    class c2[A <: Value, B <: Value]( val a: A )( implicit r2: Resolver[A and B] ) extends Resolver[A and B]
    {
        override type R = B

        override def resolve( a: O.and[A, B] ) = a.b
    }

    case class A() extends Value

    val x: A and A and A = A() and A() and A()
}

最佳答案

您的代码无法编译的原因是在指令中

 new c2( x )

编译器需要解析一个 implicit r2: Resolver[A and B]来自 x唯一可用的类型信息是 x 的类型, 即 r1.R .

这类问题需要为编译器提供更多类型信息并添加一些隐式参数。当您需要 Resolver[A and B] ,你不能使用它的 R键入以解决另一个 Resolver[r1.R and C] .
type ResolverAux[-A<:Rule,B] = Resolver[A] { type R = B }

有了这个,你可以重写你的 c2 的签名
implicit def c2[A <: Value, B <: Value, C <: Value,D<:Value]( implicit r1: ResolverAux[A and B,D], r2:Resolver[D and C] ):Resolver[A and B and C] = new Resolver[A and B and C]
  {
    override type R = C

    override def resolve( a: A and B and C ): C =
    {
      val x: r1.R = r1.resolve( a.a )
      new c2[r1.R,C]( x )
      ???
    }
  }

请注意,通过使用类型别名并引入额外的泛型参数,我可以表达关系 r1.R1 = D然后用于解析第二个隐式 r2

关于scala - 类型类和依赖类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30895305/

相关文章:

java - 手动调用PlayFramework自定义错误页面

scala - Scala 3 编译器操作中用于类型类派生的元组

scala - 是否为每个隐式类转换创建类的新实例?

scala - 如何在 Scala 中将元组隐式转换为向量

scala - 同时获得见证人和类型类

c# - 为什么静态类的成员需要声明为静态的?为什么它不只是隐含的?

scala - 为什么方法参数化而类型参数从不使用?

scala - 算法混合

scala - 如何指定多个类的宏注解扩展顺序?

haskell - 为什么参数化类型实例在不指定类型参数的情况下工作