Контекстная привязка ярлыков с более высокими типами

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

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

Ответ 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] = [email protected]

Обновление

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

Обратите внимание, что с правой стороны типа alias 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]

Ответ 2

Обратите внимание, что 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

(В академической заметке, "правильный" способ сделать это, было бы разрешить абстрагирование по видам:

    class ClassManifest[T : K][K]

    implicitly[ClassManifest[String]] // --> compiler infers ClassManifest[String][*]
    implicitly[ClassManifest[List]] // --> compiler infers ClassManifest[List][* -> *]

)