【问题标题】:Context bounds shortcut with higher kinded-types具有更高种类类型的上下文边界快捷方式
【发布时间】:2011-07-29 07:24:53
【问题描述】:

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

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...

【问题讨论】:

    标签: scala higher-kinded-types context-bound


    【解决方案1】:

    是的,但是您的上下文绑定类型必须具有更高种类的类型参数(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
    

    更新

    可以使用类型别名来允许更高种类的类型参数受一阶上下文绑定类型的限制。我们使用类型别名作为类型级函数,从一阶类型中生成更高种类的类型。对于 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]
    

    请注意,类型别名 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]
    

    【讨论】:

    • 但是ClassManifest 不需要知道它的类型参数本身比它预期的要高,只要它们绑定了更高的类型(即使使用通配符),例如为什么def test[ A, B[ A ] : ClassManifest ] {} 不允许,尽管def test[ A, B[ A ]]( implicit m: ClassManifest[ B[ A ]]) {} 允许?
    • 这就是我要说的:arg 类型是一阶还是高阶无关紧要,只要将其简化为一阶即可:implicitly[ClassManifest[List[_]]] --> 好的!所以我只是想知道为什么在这种情况下我无法获得上下文绑定的快捷方式
    • 不,这确实很重要。 List 是高阶的,List[_] 是一阶的,这要归功于存在。 ClassManifest 将只接受一阶类型参数。
    • 迈尔斯,我在这里接受你的坚持 :) 但我真的认为我们在这里很想念对方 - 我只是想知道该怎么做def test[B[_] : ClassManifest<GimmeTheDamnThingForB[_]>] {}
    【解决方案2】:

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

    这就是它起作用的原因:ClassManifest 需要一个正确的类型参数,List[T] forSome {type T} 是一个正确的类型,但 List 是一个类型构造函数。 (有关“适当”等的定义,请参阅What is a higher kinded type in 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
    

    (在学术笔记中,“正确”的做法是允许对种类进行抽象:

        class ClassManifest[T : K][K]
    
        implicitly[ClassManifest[String]] // --> compiler infers ClassManifest[String][*]
        implicitly[ClassManifest[List]] // --> compiler infers ClassManifest[List][* -> *]
    

    )

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-09
      • 2020-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多