如何在Scala中使用类型类中的依赖类型?

时间:2018-05-19 18:39:02

标签: scala types typeclass dependent-type

我想为几个不同的A -s定义B中的一对类型(trait Dep[C]C)。例如,A=String = B=View CView1(在隐式对象DepInstanceView1中定义)。然后我想在类型类定义中使用这些类型级依赖项。

如何定义具有依赖输入和返回类型的函数的类型类实例(此处为ServerSideFun[View1])(此处在DepInstanceView1中定义)?

换句话说,我希望有一个类型级别函数,它来自C -> (A,B)(这里有一个这样的类型级别映射在DepInstanceView1中定义)并在类型类中使用这个类型级别函数声明(此处为trait ServerSideFun[C])及其实例(此处为View1Conv)。

有人可以建议一下如何做到这一点吗?

或者如何修改下面的代码来编码这样的类型级别,类型依赖约束f(因为它在trait ServerSideFun[C]中隐含在类型类中?

我这样做的尝试最终导致编译错误:

source_file.scala:47: error: type mismatch;
 found   : Int(42)
 required: B
    def f[A, B] (a:A)(implicit aux:Dep.Aux[View1,A,B]):B = 42
                                                           ^
one error found

代码示例:

以下代码可以在线执行:http://rextester.com/GYWW78561

object Rextester extends App {
    println("Hello, World!3")
 }

trait Dep[C]{
  type A
  type B
}

trait View1
trait View2


object Dep{

  type Aux[C0, A0, B0]=  Dep[C0] {type A=A0; type B= B0}

  implicit object DepInstanceView1  extends  Dep[View1] {
    type A=String
    type B=Int
  } 
}

trait ServerSideFun[C]
{
   def f[A,B] (a:A)(implicit aux:Dep.Aux[C,A,B]):B
}

object ServerSideFun {
  implicit object View1Conv extends ServerSideFun[View1]{
    def f[A, B] (a:A)(implicit aux:Dep.Aux[View1,A,B]):B = 42
  }
}

编辑:

我更新了代码以澄清意图:http://rextester.com/YVBV30174

是:

1)定义几个View - s:

  • trait View1
  • trait View2

2)为每个View - s定义一个单独的类型级别映射View -> (A,B),例如:

    View1-> (String,Int)
  • DepInstanceView1View2-> (String,String)
  • DepInstanceView2

3)可以有类型类ServerSideFun的几种不同实现,例如:

  • object ServerSideFun
  • 中的一个
  • object ServerSideFunAlternativeImplementation中的另一个。

本质上

  • 类型类ServerSideFun[C]的所有实例应遵循View -> (A,B)中定义的类型级别映射object Dep
  • 因此,对于给定的f,函数View的每个定义(实现)必须采用类型为A的输入参数并返回类型{{1}的结果}}。

以下是代码:

B

1 个答案:

答案 0 :(得分:1)

如果ServerSideFun[C]应该包含某些类型f: A => BA的函数B的实现,那么ServerSideFun[C]显然必须知道类型AB是,否则它必须从来自特征f之外的某些部分组成函数ServerSideFun[C]。但是我们可以将type Atype B加入ServerSideFun[C],然后完全放弃Dep[C]

trait View1
trait View2

trait ServerSideFun[C]{
  type A
  type B
  def f(a: A): B
}

object ServerSideFun {
  implicit object View1Conv extends ServerSideFun[View1] {
    type A = String
    type B = Int
    def f(a: String): Int = 42
  }
}

如果您愿意,可以重新引入Dep[C],然后Dep[C] ServerSideFun[C]延长{/ 1}}:

trait Dep[C]{
  type A
  type B
}

trait View1
trait View2

object Dep {
  trait DepInstanceView1 extends Dep[View1] {
    type A = String
    type B = Int
  } 
}

trait ServerSideFun[C] extends Dep[C] {
  def f(a: A): B
}

object ServerSideFun {
  implicit object View1Conv 
    extends ServerSideFun[View1] 
    with Dep.DepInstanceView1 {

    def f(a: String): Int = 42
  }
}

如果f不是某些"天然成分"完全通用的函数,然后在某些时候你必须在已知fA的上下文中写下B的正文。在体内写下具体的42,但同时在A从外部带来完全未指明的BDep.Aux[View1,A,B]并不起作用。