为什么这会无效使用Scala的抽象类型? [英] Why is this an invalid use of Scala's abstract types?

查看:97
本文介绍了为什么这会无效使用Scala的抽象类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有此代码:

class A extends Testable { type Self <: A }

class B extends A { type Self <: B }

trait Testable {
    type Self
    def test[T <: Self] = {}
}

object Main {
    val h = new A
    // this throws an error
    h.test[B]
}

我的错误是:

error: type arguments [B] do not conform to method test's type parameter bounds [T <: Main.h.Self]
    h.test[B]

这个问题中,这是由于路径相关的类型.任何人都可以弄清楚如何拥有T< ;: Self,而不会遇到依赖于路径的类型问题吗?

任何帮助将不胜感激.

解决方案

您的代码必须像这样:

// --- fictional scala syntax ---
class A extends Testable { type Self = A }
class B extends A { override type Self = B }

但是在当前版本的scala中,它不可能.

我会提出一些建议(不超过使用依赖路径的类型,而是另一种),它符合您的要求.

a)使用Type-class模式作为测试方法;

b)使用隐式参数来符合类型关系.

类层次结构:

trait Testable
class A extends Testable
class B extends A

符合特征:

trait Conforms[X, Y]

可测试的类型类:

object TestableTypeClass {
  implicit def testMethod[T <: Testable](testable : T) = new {
    def test[X](implicit ev : Conforms[X, T]) = {}
  }
}

伴随对象中的

test方法类型参数条件:

object A {
  // P <: A is your conditon (Self <: A) for class A
  implicit def r[P <: A] = new Conforms[P , A] {}
}
object B {
  // P <: B is your conditon (Self <: B) for class B
  implicit def r[P <: B] = new Conforms[P , B] {}
}

测试:

import TestableTypeClass._

val a = new A
a.test[A]    // - Ok
a.test[B]    // - Ok

val b = new B
// b.test[A] // - did not compile
b.test[B]    // - Ok

更新:

1)可以在一个对象中收集所有隐式对象,在这种情况下,需要导入具有隐式对象的对象(之前在伴随对象中隐式范围的规则不需要该对象):

object ImplicitContainer {
  implicit def r1[P <: A] = new Conforms[P , A] {}
  implicit def r2[P <: B] = new Conforms[P , B] {}
} 

并使用:

import TestableTypeClass._
import ImplicitContainer._

val a = new A
a.test[A]
a.test[B]   

2,3)为2类型参数X& Y

X-用于将来的类型约束(此约束来自参数方法)

Y-用于确定将为其定义类型约束的类型

根据Comforms实例类型隐式选择参数,并且这种设计的想法是结合使用X&是

类型类TestableTypeClass中的

类型Y,是通过test方法从Testable隐式转换为匿名类而捕获的Y类型,而类型test方法调用中捕获的.

一个主要特征是Conforms特征的不变性,这就是为什么隐式函数不是模棱两可并正确管理绑定规则的原因.

为了更好地理解,又给出了一个具有更严格规则的示例:

//...
class C extends B

object ImplicitContainer {
  implicit def r1[P <: A] = new Conforms[P , A] {}
  implicit def r2[P](implicit ev : P =:= B) = new Conforms[P , B] {}
  implicit def r3[P <: C] = new Conforms[P , C] {}
}


import TestableTypeClass._
import ImplicitContainer._

val b = new B
//b.test[A]    // - did not compile
b.test[B]      // - Ok
//b.test[C]    // - did not compile

I have this code:

class A extends Testable { type Self <: A }

class B extends A { type Self <: B }

trait Testable {
    type Self
    def test[T <: Self] = {}
}

object Main {
    val h = new A
    // this throws an error
    h.test[B]
}

And my error is:

error: type arguments [B] do not conform to method test's type parameter bounds [T <: Main.h.Self]
    h.test[B]

On this question, it was said that this was due to path dependent types. Can anyone figure out how to have T <: Self, without having the path-dependent types problem?

Any help would be appreciated.

解决方案

Your code need to be looks like:

// --- fictional scala syntax ---
class A extends Testable { type Self = A }
class B extends A { override type Self = B }

But it is imposible in current version of scala.

I would propose little bit long way (not longer than using path dependent types but another), and it conforms your requirements.

a) Use Type-class pattern for test method;

b) Use implicit parameters for conforms type relations.

Class hierarchy:

trait Testable
class A extends Testable
class B extends A

Conforms trait:

trait Conforms[X, Y]

Testable Type-class:

object TestableTypeClass {
  implicit def testMethod[T <: Testable](testable : T) = new {
    def test[X](implicit ev : Conforms[X, T]) = {}
  }
}

test method type parameter conditions in companion objects:

object A {
  // P <: A is your conditon (Self <: A) for class A
  implicit def r[P <: A] = new Conforms[P , A] {}
}
object B {
  // P <: B is your conditon (Self <: B) for class B
  implicit def r[P <: B] = new Conforms[P , B] {}
}

Tests:

import TestableTypeClass._

val a = new A
a.test[A]    // - Ok
a.test[B]    // - Ok

val b = new B
// b.test[A] // - did not compile
b.test[B]    // - Ok

UPDATE:

1) It is possible to collect all implicits in one object, and in this case object with implicits need to import (it is not needed before by rules of implicit scope in companion object):

object ImplicitContainer {
  implicit def r1[P <: A] = new Conforms[P , A] {}
  implicit def r2[P <: B] = new Conforms[P , B] {}
} 

and using:

import TestableTypeClass._
import ImplicitContainer._

val a = new A
a.test[A]
a.test[B]   

2,3) trait Conforms defined for 2 type parameter X & Y

X - used for future type constraint (and this constraint come from parametric method)

Y - used for determine the type for which will be define type constraint

implicit parameter choise by Comforms instance type, and idea of this design is playing with combinations X & Y

in Type-class TestableTypeClass type Y captured by implicit conversion from Testable to anonimous class with test method, and type X captured in test method call.

And a main feature is invariance of Conforms trait, this is why implicits is not ambiguous and correctly manage bound rules.

And for better understanding, one more example with more strict rules:

//...
class C extends B

object ImplicitContainer {
  implicit def r1[P <: A] = new Conforms[P , A] {}
  implicit def r2[P](implicit ev : P =:= B) = new Conforms[P , B] {}
  implicit def r3[P <: C] = new Conforms[P , C] {}
}


import TestableTypeClass._
import ImplicitContainer._

val b = new B
//b.test[A]    // - did not compile
b.test[B]      // - Ok
//b.test[C]    // - did not compile

这篇关于为什么这会无效使用Scala的抽象类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆