2016-11-13 9 views
4
trait Encoder[From, To] { 
    def encode(x: From): To 
} 
object Encoder { 
    implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] { 
    def encode(x: Thing): String = x.toString 
    } 
} 

trait Config { 
    type Repr 
} 
class MyConfig extends Config { type Repr = String } 
//class ConcreteConfig { type Repr = String } 

class Api[T](val config: Config) { 
    def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {} 
} 

case class Thing(a: Int) 

object Test extends App { 
    import Encoder._ 

    val api = new Api[Thing](new MyConfig) 
    api.doSomething(Thing(42)) 
} 

api.doSomethingへの呼び出しがコンパイルに失敗します。スカラ:パス依存型の型クラスのインスタンスの暗黙の検索

could not find implicit value for parameter encoder: Encoder[Thing,Test.api.config.Repr] 

それはConcreteConfigをとるように私はclass Api[T]のコンストラクタのシグネチャを変更した場合コンパイラはconfig.Repr == Stringと暗黙のルックアップが成功したことを伝えることができます。しかし、これは私のユースケースではうまくいかないでしょう。

暗黙の参照を導く他の方法はありますか?私は型の情報を失っているのですか?

答えて

0

これは、config.Reprが安定したパスではないため、達成できません。 configの実行時の値がMyConfig型であっても、コンパイラはconfig.Repr = Stringを判別できません。

この

は、あなたがREPRの正確な種類が何であるかをコンパイラに教えてくれますAPIの型パラメータとして、具体的な設定インスタンスを提供できる場合にのみ動作するように起こっている:

class Api[T, C <: Config](val config: C) { 
    def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {} 
} 

object Test extends App { 
    import Encoder._ 

    val api = new Api[Thing, MyConfig](new MyConfig) 
    api.doSomething(Thing(42)) 
} 
+0

'api.config.Repr' _は安定したパスですが、2番目の文は正しいですが。 –

0

推測タイプは一度に一歩。また、ここでは値に依存する型を使用する理由は見当たりません(または、どこでも問題ありません)。

trait Encoder[From, To] { 
    def encode(x: From): To 
} 
object Encoder { 

    implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] { 
    def encode(x: Thing): String = x.toString 
    } 
} 

trait Config { 
    type Repr 
} 
class MyConfig extends Config { type Repr = String } 
// class ConcreteConfig { type Repr = String } 

case class Api[T, C <: Config](val config: C) { 
    def doSomething(value: T)(implicit encoder: Encoder[T, C#Repr]): Unit =() 
} 

case class ApiFor[T]() { 
    def withConfig[C <: Config](config: C): Api[T,C] = Api(config) 
} 

case class Thing(a: Int) 

object Test extends App { 
    import Encoder._ 

    val api = ApiFor[Thing] withConfig new MyConfig 
    // compiles! 
    api.doSomething(Thing(42)) 
} 
関連する問題