具有更高kinded类型的上下文边界快捷方式

0__*_*0__ 11 scala higher-kinded-types context-bound

是否可以使用更高kinded类型的上下文边界语法快捷方式?

trait One { def test[W   : ClassManifest]: Unit } // first-order ok
trait Two { def test[W[_]: ClassManifest]: Unit } // not possible??
trait Six { def test[W[_]](implicit m: ClassManifest[W[_]]): Unit } // hmm...
Run Code Online (Sandbox Code Playgroud)

Mil*_*bin 12

是的,它是,但您的上下文绑定类型必须具有更高的kinded类型参数(ClassManifest不具有).

scala> trait HKTypeClass[CC[_]]
defined trait HKTypeClass

scala> implicit def listHKTC = new HKTypeClass[List] {}
listHKTC: java.lang.Object with HKTypeClass[List]

scala> def frob[CC[_] : HKTypeClass] = implicitly[HKTypeClass[CC]]
frob: [CC[_]](implicit evidence$1: HKTypeClass[CC])HKTypeClass[CC]

scala> frob[List]
res0: HKTypeClass[List] = $anon$1@13e02ed
Run Code Online (Sandbox Code Playgroud)

更新

可以使用类型别名来允许更高级别的类型参数受一阶上下文绑定类型的限制.我们使用类型别名作为类型级函数来从一阶类型中创建一个更高级的类型.对于ClassManifest,它可以像这样,

scala> type HKClassManifest[CC[_]] = ClassManifest[CC[_]]
defined type alias HKClassManifest

scala> def frob[CC[_] : HKClassManifest] = implicitly[HKClassManifest[CC]]         
test: [CC[_]](implicit evidence$1: HKClassManifest[CC])HKClassManifest[CC]

scala> frob[List]                                                       
res1: HKClassManifest[List] = scala.collection.immutable.List[Any]
Run Code Online (Sandbox Code Playgroud)

请注意,在类型别名CC [_]的右侧是一阶类型...这里的下划线是通配符.因此,它可以用作ClassManifest的类型参数.

更新

为了完整性,我应该注意类型别名可以使用类型lambda内联,

scala> def frob[CC[_] : ({ type ?[X[_]] = ClassManifest[X[_]] })#?] = implicitly[ClassManifest[CC[_]]]     
frob: [CC[_]](implicit evidence$1: scala.reflect.ClassManifest[CC[_]])scala.reflect.ClassManifest[CC[_]]

scala> frob[List]
res0: scala.reflect.ClassManifest[List[_]] = scala.collection.immutable.List[Any]
Run Code Online (Sandbox Code Playgroud)


Adr*_*ors 5

请注意,这implicitly[ClassManifest[List[_]]]是的缩写implicitly[ClassManifest[List[T] forSome {type T}]]

这就是它起作用的原因:ClassManifest需要一个适当的类型参数,并且List[T] forSome {type T}是适当的类型,但是List是类型构造函数。(有关“适当”等的定义,请参见Scala中什么是更高种类的类型?

为了使两者ClassManifest[List[String]]同时ClassManifest[List]起作用,我们需要以ClassManifest某种方式重载带有各种类型参数的版本,例如:

class ClassManifest[T] // proper type
class ClassManifest[T[_]] // type constructor with one type parameter
class ClassManifest[T[_, _]] // type constructor with two type parameters
// ... ad nauseam
Run Code Online (Sandbox Code Playgroud)

(在学术上,做到这一点的“正确”方法是允许对种类进行抽象:

    class ClassManifest[T : K][K]

    implicitly[ClassManifest[String]] // --> compiler infers ClassManifest[String][*]
    implicitly[ClassManifest[List]] // --> compiler infers ClassManifest[List][* -> *]
Run Code Online (Sandbox Code Playgroud)