Этот вопрос касается ограничения системы неявного разрешения Scala, которую я использовал несколько раз при использовании Scalaz, и это не имеет большого смысла для меня. Я переделал эту проблему в версию, отличную от Scalaz, ниже, но я рад предоставить дополнительную информацию о мотивации, если это необходимо.
Предположим, что у меня есть пара классов типов, которые что-то свидетельствуют о конструкторе типа:
import scala.language.higherKinds
trait Foo[F[_]]
trait Bar[F[_], A]
Теперь также предположим, что если у меня есть экземпляр Foo
для некоторого F
, я знаю, что у меня также есть экземпляр Foo
для Bar[F, _]
:
implicit def barFoo[F[_]: Foo] = new Foo[({type L[X] = Bar[F, X]})#L] {}
У меня также есть экземпляры для List
и правой части Either
:
implicit object listFoo extends Foo[List]
implicit def eitherFoo[A] = new Foo[({type L[X] = Either[A, X]})#L] {}
Теперь довольно ясно, что я должен был бы написать следующее:
type BarList[X] = Bar[List, X]
implicitly[Foo[BarList]]
Или, что эквивалентно:
implicitly[Foo[({type L[X] = Bar[List, X]})#L]]
И действительно, обе работают точно так, как ожидалось.
Итак, я пробую следующее:
type StringOr[X] = Either[String, X]
type BarStringOr[X] = Bar[StringOr, X]
И затем:
scala> implicitly[Foo[BarStringOr]]
res2: Foo[BarStringOr] = [email protected]
Опять же, никаких сюрпризов здесь нет. Но затем я пытаюсь:
implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]]
И я получаю следующее:
<console>:15: error: could not find implicit value for parameter e: Foo[[X]Bar[[X]scala.util.Either[String,X],X]]
implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]]
^
Обратите внимание, что я не имею проблемы с выводом необходимого экземпляра Foo
для StringOr
или вызовом barFoo
явно, чтобы получить желаемый экземпляр:
scala> implicitly[Foo[StringOr]]
res4: Foo[StringOr] = [email protected]
scala> barFoo[StringOr]
res5: Foo[[X]Bar[StringOr,X]] = [email protected]
У меня возникли проблемы с определением того, какое важное различие может быть между случаями List
и StringOr
, которые позволяют использовать версию типа лямбда для первой, но не последней.
Я пробовал это на Scala 2.10.0-RC5 и 2.9.2. Добавление ковариации по всему не помогает.
Я пропустил что-то очевидное? Может ли кто-нибудь указать мне на что-то в спецификации, которая поможет мне понять это или предыдущие обсуждения подобных проблем?