2015-01-31 4 views
3

С помощью следующего кода я получаю «расходящийся неявное расширение» ошибка в 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, чтобы извлечь выгоду из более высоких relative weight. Передача аргумента явно (extends Bar[(Array[Env], ((Int,A)) => B)]()(complexFoo)) действительно работает, но я бы очень хотел ее избежать (Bar1 - это фактически сгенерированный код, и это сделало бы поколение более сложным). Итак, есть ли другой способ избежать ошибки?

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

ответ

1

Изменение

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

в

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

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

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

+0

Не знаю достаточного количества внутренних решений, чтобы понять, почему это так. – al3xar

+0

Спасибо. К сожалению, это означает, что пример был упрощен; Мне действительно нужно использовать 'eA' и т. Д. Себя в коде. И добавление 'foo' вместо замены их приводит к множеству противоречивых имплицитов. –

+1

Вы также можете попробовать использовать бесформенный 'Lazy', он обычно решает много неявных расходящихся расширений. Но на данный момент это не очень хорошо относится к переменным типа, так что это может быть немного сложнее (я думал, что «Lazy» был первым решением, но оказалось, что это не обязательно) – al3xar