Контекстные ярлыки с более высокими типами - PullRequest
11 голосов
/ 04 апреля 2011

Можно ли использовать сочетание синтаксиса границ контекста с типами с более высоким родом?

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

Ответы [ 2 ]

12 голосов
/ 04 апреля 2011

Да, это так, но тип, связанный с контекстом, должен иметь более высокий параметр типа 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

Обновление

Можно использовать псевдоним типа, чтобы позволить параметру типа с более высоким родом быть связанным типом контекста первого порядка.Мы используем псевдоним типа в качестве функции уровня типа, чтобы сделать тип с более высоким родом из типа первого порядка.Для 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.

Обновление

Для полноты следует отметить, что псевдоним типа может быть встроен с использованием типа лямбда,

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]
5 голосов
/ 22 июня 2011

Обратите внимание, что implicitly[ClassManifest[List[_]]] - это сокращение от implicitly[ClassManifest[List[T] forSome {type T}]].

Вот почему это работает: ClassManifest ожидает правильный аргумент типа, а List[T] forSome {type T} - правильный тип, но List - конструктор типа.(См. Что такое тип с более высоким родом в Scala? для определения "правильного" и т.каким-то образом перегрузить 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][* -> *]

)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...