Този въпрос е за ограничение на имплицитната система за разделителна способност на 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] = $anon$1@39a6c855
Тук отново няма изненади. Но след това опитвам:
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] = $anon$1@3eaac006
scala> barFoo[StringOr]
res5: Foo[[X]Bar[StringOr,X]] = $anon$1@179fbfea
Имам проблем да идентифицирам каква важна разлика може да има между случаите List
и StringOr
, която позволява на версията тип ламбда да работи за първия, но не и за втория.
Опитах това на Scala 2.10.0-RC5 и 2.9.2. Добавянето на ковариация навсякъде не помага.
Пропускам ли нещо очевидно? Може ли някой да ме насочи към нещо в спецификацията, което би ми помогнало да разбера това, или към предишни дискусии на подобни проблеми?