首页 > 解决方案 > 如何在 Scala 的类型类中使用依赖类型?

问题描述

我想为几个不同的-s定义一对类型(ABin )。例如,for = (在隐式对象中定义)。然后我想在类型类定义中使用这些类型级别的依赖关系。 trait Dep[C]CA=StringB=ViewCView1DepInstanceView1

如何定义一个类型类实例(此处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 :

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

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

本质上

这是代码:

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
  } 

  implicit object DepInstanceView2  extends  Dep[View2] {
    type A=String
    type B=String
  } 
}

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
  }

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



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

  implicit object View2Conv extends ServerSideFun[View2]{
    def f[A, B] (a:A)(implicit aux:Dep.Aux[View2,A,B]):B = "43"
  }

}

标签: scalatypestypeclassdependent-type

解决方案


如果ServerSideFun[C]应该包含f: A => B某些类型的函数的实现Aand B,那么ServerSideFun[C]显然必须知道类型AB是什么,否则它将必须f从来自 trait 之外的某些部分组成函数ServerSideFun[C]。但是我们可以包含type Atype BServerSideFun[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]

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它的主体。在体内写下混凝土,但同时将完全未指定的内容从外部引入是行不通的。fAB42ABDep.Aux[View1,A,B]


推荐阅读