如何在 Scala 中的类型 类 中使用依赖类型?
How to use dependent types inside type classes in Scala?
我想为几个不同的 C
-s 定义一对类型(A
和 trait Dep[C]
中的 B
)。例如,A=String
和 B=View
代表 C
=View1
(在隐式对象 DepInstanceView1
中定义)。然后我想在 type class 定义中使用这些类型级别的依赖关系。
如何定义类型 class 实例(此处 ServerSideFun[View1]
),它具有依赖输入的函数和 return 类型(此处在 DepInstanceView1
中定义)?
换句话说,我想要一个从 C -> (A,B)
开始的类型级函数(这里在 DepInstanceView1
中定义了一个这样的类型级映射)并在输入 class 声明(此处 trait ServerSideFun[C]
)及其实例(此处 View1Conv
)。
有人可以建议一种方法吗?
或者如何修改下面的代码以编码这种类型级别的方法,在类型 class 中对 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)
在 DepInstanceView1
View2-> (String,String)
在 DepInstanceView2
3) 使得 class ServerSideFun
类型的多个不同实现成为可能,例如:
object ServerSideFun
中的一个
- 另一个
object ServerSideFunAlternativeImplementation
.
本质上 :
- 所有 类型 class
ServerSideFun[C]
的实例应遵守 object Dep
中定义的类型级别映射 View -> (A,B)
。
- 因此,对于给定的
View
,函数 f
的每个定义(实现)都必须采用 A
和 return 类型的输入参数B
类型的结果。
代码如下:
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"
}
}
如果 ServerSideFun[C]
应该包含某些类型 A
和 B
的函数 f: A => B
的实现,那么 ServerSideFun[C]
显然必须知道A
和 B
是什么类型,否则它必须从特征 ServerSideFun[C]
之外的一些部分组成函数 f
。但是我们可以将 type A
和 type 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]
:
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
不是一些 "natural composition" 完全通用的函数,那么在某些时候你将不得不在 [=14= 的上下文中写下 f
的主体] 和 B
是已知的。在正文中写下一个具体的42
,但同时从外部将完全未指定的A
和B
引入Dep.Aux[View1,A,B]
是行不通的。
我想为几个不同的 C
-s 定义一对类型(A
和 trait Dep[C]
中的 B
)。例如,A=String
和 B=View
代表 C
=View1
(在隐式对象 DepInstanceView1
中定义)。然后我想在 type class 定义中使用这些类型级别的依赖关系。
如何定义类型 class 实例(此处 ServerSideFun[View1]
),它具有依赖输入的函数和 return 类型(此处在 DepInstanceView1
中定义)?
换句话说,我想要一个从 C -> (A,B)
开始的类型级函数(这里在 DepInstanceView1
中定义了一个这样的类型级映射)并在输入 class 声明(此处 trait ServerSideFun[C]
)及其实例(此处 View1Conv
)。
有人可以建议一种方法吗?
或者如何修改下面的代码以编码这种类型级别的方法,在类型 class 中对 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)
在DepInstanceView1
View2-> (String,String)
在DepInstanceView2
3) 使得 class ServerSideFun
类型的多个不同实现成为可能,例如:
object ServerSideFun
中的一个
- 另一个
object ServerSideFunAlternativeImplementation
.
本质上 :
- 所有 类型 class
ServerSideFun[C]
的实例应遵守object Dep
中定义的类型级别映射View -> (A,B)
。 - 因此,对于给定的
View
,函数f
的每个定义(实现)都必须采用A
和 return 类型的输入参数B
类型的结果。
代码如下:
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"
}
}
如果 ServerSideFun[C]
应该包含某些类型 A
和 B
的函数 f: A => B
的实现,那么 ServerSideFun[C]
显然必须知道A
和 B
是什么类型,否则它必须从特征 ServerSideFun[C]
之外的一些部分组成函数 f
。但是我们可以将 type A
和 type 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]
:
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
不是一些 "natural composition" 完全通用的函数,那么在某些时候你将不得不在 [=14= 的上下文中写下 f
的主体] 和 B
是已知的。在正文中写下一个具体的42
,但同时从外部将完全未指定的A
和B
引入Dep.Aux[View1,A,B]
是行不通的。