Обходной путь для расходящейся ошибки неявного раскрытия в Scala 2.10

С помощью следующего кода я получаю ошибку «расходящееся неявное расширение» в Scala 2.10, хотя существует уникальный способ создания неявного:

class Foo {
  trait Foo[A]
  abstract class Bar[A](implicit e: Foo[A])

  implicit val intFoo: Foo[Int] = ???
  implicit def pairFoo[A, B](implicit ea: Foo[A], eb: Foo[B]): Foo[(A, B)] = ???
  implicit def funcFoo[A, B](implicit ea: Foo[A], eb: Foo[B]): Foo[A => B] = ???
  implicit def arrayFoo[A](implicit e: Foo[A]): Foo[Array[A]] = ???
  def foo[A](implicit e: Foo[A]): Foo[A] = e
  class Bar1[A, B, Env](implicit eA: Foo[A], eB: Foo[B], eEnv: Foo[Env])
    extends Bar[(Array[Env], ((Int,A)) => B)]
}

> compile
[info] Compiling 1 Scala source to /home/aromanov/IdeaProjects/playground/target/scala-2.10/classes...
[error] /home/aromanov/IdeaProjects/playground/src/main/scala/Foo.scala:15: diverging implicit expansion for type Foo1.this.Foo[(Array[Env], ((Int, A)) => B)]
[error] starting with method pairFoo in class Foo
[error]   class Bar1[A, B, Env](implicit eA: Foo[A], eB: Foo[B], eEnv: Foo[Env])
[error]                        ^

Я добавил более конкретное неявное преобразование, надеясь, что оно будет выбрано:

implicit def complexFoo[A, B, Env](implicit eA: Foo[A], eB: Foo[B], eEnv: Foo[Env]): Foo[(Array[Env], ((Int,A)) => B)] =
  pairFoo(arrayFoo(eEnv), foo[((Int, A)) => B])

Это не помогает. Не переносится и complexFoo и Bar1 в подкласс Foo, чтобы получить выгоду от более высокого относительного веса. Явная передача аргумента (extends Bar[(Array[Env], ((Int,A)) => B)]()(complexFoo)) действительно работает, но я бы очень хотел избежать этого (Bar1 - это фактически сгенерированный код, и это усложнит генерацию). Итак, есть ли другой способ избежать ошибки?

Это нормально работает в 2.11.5, но пока мы не можем удалить совместимость с 2.10.


person Alexey Romanov    schedule 31.01.2015    source источник


Ответы (1)


Изменение

class Bar1[A, B, Env](implicit eA: Foo[A], eB: Foo[B], eEnv: Foo[Env])
  extends Bar[(Array[Env], ((Int,A)) => B)]

to

class Bar1[A, B, Env](implicit foo: Foo[(Array[Env], ((Int,A)) => B)])
  extends Bar[(Array[Env], ((Int,A)) => B)]

заставляет ваш код компилироваться. По-видимому, здесь нужно прямо указать scalac 2.10 (foo), и он не может создать его самостоятельно (из eA, eB, eEnv).

Надеюсь, ваш инструмент генерации кода сможет сгенерировать именно это.

person Alex Archambault    schedule 31.01.2015
comment
Не знаю достаточно о внутреннем устройстве неявного разрешения, чтобы понять, почему это так. - person Alex Archambault; 31.01.2015
comment
Спасибо. К сожалению, это означает, что пример был слишком упрощен; Мне действительно нужно использовать eA и т. Д. В коде. И добавление foo вместо их замены приводит к множеству противоречивых имплицитов. - person Alexey Romanov; 31.01.2015
comment
Вы также можете попробовать использовать shapeless'Lazy, он обычно решает множество неявных расходящихся расширений. Но на данный момент это не очень хорошо работает с переменными типа, поэтому это может быть немного сложно (я думал, что Lazy было первым решением, но оказалось, что в этом нет необходимости) - person Alex Archambault; 31.01.2015