2016-12-05 8 views
2

I次のコードを持っています。エラーとインポート暗黙

case class Custom(value: Int) 
case class Custom2(value: Float) 

case class MappedEncoding[I, O](f: I => O) 

trait Decoders { 
    type BaseDecoder[T] =() => T 
    type Decoder[T] <: BaseDecoder[T] 
} 

trait ConcreteDecoders extends Decoders { 
    type Decoder[T] = ConcreteDecoder[T] 

    case class ConcreteDecoder[T](decoder:() => T) extends BaseDecoder[T] { 
    def apply(): T = decoder() 
    } 

    implicit def optionDecoder[T](implicit d: Decoder[T]): Decoder[Option[T]] = 
    ConcreteDecoder[Option[T]](() => Some(d())) 

    implicit def mappedDecoder[I, O](implicit mapped: MappedEncoding[I, O], decoder: Decoder[I]): Decoder[O] = 
    ConcreteDecoder[O](() => mapped.f(decoder())) 

    implicit def intDecoder: Decoder[Int] = ConcreteDecoder[Int](() => 1) 
    implicit def floatDecoder: Decoder[Float] = ConcreteDecoder(() => 1) 

} 

class ConcreteContext extends ConcreteDecoders { 
} 

case class TestObject() { 

    implicit val customDecoder = MappedEncoding[Int, Custom](Custom) 
    implicit val custom2Encoder = MappedEncoding[Custom2, Float](_.value) // 1 
    implicit val custom2Decoder = MappedEncoding[Float, Custom2](Custom2) 

    def a(c: ConcreteContext): Unit = { 
    import c._ 
    implicitly[Decoder[Option[Custom]]] // 2 
// implicitly[Decoder[Float]]   // 3 
    implicitly[Decoder[Option[Float]]] 
    () 
    } 
} 


object Main extends App { 
    implicit val c = new ConcreteContext() 

    TestObject().a(c) 
    // TestObject(a).() 
} 

そして、それはScalaの2.11.8でコンパイルしないと2.12.0:

diverging implicit expansion for type c.Decoder[Option[Float]] 
[error] starting with method intDecoder in trait ConcreteDecoders 
[error]  implicitly[Decoder[Option[Float]]] 

-Xlog-implicitsオプションを使用すると、長い出力を与えるが、最も興味深い部分がある:

floatDecoder is not a valid implicit value for c.Decoder[Float] because: 
[info] diverging implicit expansion for type c.Decoder[T] 
[info] starting with method intDecoder in trait ConcreteDecoders 
[info]  implicitly[Decoder[Option[Float]]] 

methodパラメーターからcaseクラスのコンストラクターパラメーターにc: CustomContextを移動すると、コンパイルされます。私はそれが検索範囲を暗黙に変更するかもしれないと思った。また

次のいずれかの操作は、それをコンパイルします:

  • コメント1(==ライン1)でマークされた行をコメント
  • コメント行2
  • コメントを解除行3

implicitly[Decoder[Option[Float]]]の解決に影響する状態で、implicitly[Decoder[Option[Custom]]]がScalaコンパイラを終了させるように見えます。

どうしてこのようなことが起こっていて、メソッドパラメータからc: ConcreteContextを移動せずにコンパイルするにはどうすればよいですか?

P.S.これは問題を再現する簡単なコードです。実際のコードははるかに複雑で、ConcreteContextがメソッドパラメータとして渡されたときにサポートする必要があります。

+0

を作るためにあなたのmappedDecoder

として
import shapeless.Lazy implicit def mappedDecoder[I, O] (implicit mapped: MappedEncoding[I, O], decoder: Lazy[Decoder[I]]): Decoder[O] = ConcreteDecoder[O](() => mapped.f(decoder.value())) 

を書き換えることができます。これは[SI-9625](https://issues.scala-lang.org/browse/SI-9625)と多少関連しているようです。この問題は、メソッドのparamをコンストラクタparamに変換すると消えます。 sidenoteでは、 'Decoder'を' Function0'のサブタイプにすることは最善の考えではないかもしれません。 –

+0

@ Jasper-M http://stackoverflow.com/q/40391732/746347のため、 'Decoder'を' Function0'のサブタイプにしました。 – mixel

+1

明らかな回避策 'val c0:c.type = c; import c0._' def a(c:ConcreteContext):Unit'はあなたのニーズに十分ですか? –

答えて

1

これは完全な答えではありません。

mappedEncodercustom2Encoder + custom2Decoderのペアで作成された別の暗黙的な言葉がループから外れてしまうという満足のいく説明がありません。私はimplicitly[Decoder[Float]]の存在がcustom2...ループより優先してfloatDecoderを上回っていると推測できます。

shapeless.Lazyという最適な解決策があります。このようなより恐ろしい状況に対処するために、分解の代わりにLowPriorityを使用することがあります。

あなただけの何かがここに間違いなく怪しいです元のコードの作業に

関連する問題