Система типов Scala, не может найти общего предка в строке - PullRequest
1 голос
/ 07 октября 2019

Я нахожусь в сильно типизированной системе с некоторыми универсальными методами, объявленными как def execute]C <: A#C](cmd: C):EitherT[Future, Fail, Seq[A#E]] (где A - универсальный тип для класса.

Это работает хорошо. Однако в моих тестах, когда я имитируюэти вызовы, я должен явно набрать супер-типы Fail и A#E, или мой код не может скомпилироваться.

// Event is the base type of Receiver#E
val event:Event = SubOfEvent()
handler.execute(any[SubOfCommand]) returns Seq(event).asRightT[Future, Fail]

val fail:Fail = SubOfFail()
handler.execute(any[SubOfCommand]) returns fail.asLeftT[Future, Seq[Receiver#E]]

Если я встраиваю объявления event или fail, у меня есть Несоответствие типов :

  found   : cats.data.EitherT[scala.concurrent.Future,SubOfFail,scala.collection.immutable.Seq[SubOfEvent]]
  required: cats.data.EitherT[scala.concurrent.Future,Fail,scala.collection.immutable.Seq[Receiver#E]]
     (which expands to)  cats.data.EitherT[scala.concurrent.Future,Fail,scala.collection.immutable.Seq[Event]]
 Note: SubOfFail <: Fail, but class EitherT is invariant in type A.
 You may wish to define A as +A instead. (SLS 4.5)
     handler.execute(any[SubOfCommand]) returns SubOfFail().asLeftT[Future,
                                                                   ^

Я понимаю сообщение о том, что EitherT инвариантен в типе A. Но я ожидал, что он сможет перевести EitherT[F, SubOfA, B] как EitherT[F, SubOfA.asInstanceOf[A], B].

Может ли кто-нибудь помочь мне выявить изъян в моих рассуждениях?

Спасибо

1 Ответ

1 голос
/ 07 октября 2019

Но я ожидал, что он сможет перевести EitherT[F, SubOfA, B] как EitherT[F, SubOfA.asInstanceOf[A], B].

Быть инвариантом означает, что невозможно «перевести» таким образом:EitherT[F, SubOfA, B] просто не EitherT[F, A, B].

Теперь отдельный вопрос состоит в том, почему тип для fail не выводится как Fail, несмотря на ожидаемый тип для всего fail.asLeftT[Future, Seq[Receiver#E]]. И ответ здесь таков: вывод типа Scala просто не работает таким образом;при вводе expression.method(...) сначала он наберет expression и не сможет использовать ожидаемый тип возвращаемого значения method.

. Вы все еще можете записать их встроенными, но вам нужно указать тип:

(SubOfFail(): Fail).asLeftT[Future, Seq[Receiver#E]]

В случае Seq также будет работать явный параметр типа:

Seq[Event](SubOfEvent()).asRightT[Future, Fail]
...