2017-10-22 17 views
0

例えば型生成者の抽象型メンバーをスカラーで推論できますか?

trait F[T] { type Out } 

object F { 
    type Aux[T, out] = F[T] { type Out = out } 
} 

def glhf[t, out](implicit f: F.Aux[t, out]): out = ??? 

私は、これは、抽出のいずれかの種類(さえ複雑なクロス暗黙の型変数)のための魔法のように動作し、暗黙のパラメータ(ラ・型崩れ)の抽象型メンバーを抽出しようとしています。

ただし、抽象型メンバーが型のコンストラクタであり、単純型ではない場合、コンパイラは呼び出しポイントで型変数を統一することができません。

私は奇妙なコンパイルエラーがある小さなテストケースを作成しました。コンパイラのエラーはあまり意味を持たないので、私はこれがコンパイラのバグかどうか疑問に思っていますか?エラーメッセージの詳細については、コードサンプルを参照してください。

余分なメッセージはscala-2.12.4,-Xlog-implicits、さらに問題の場合は-Ypartial-unificationでコンパイルされます。

incubator/Main.scala

package incubator 

object wat { 

    /** 
    * A "type class", "implicit evidence" type, etc... 
    * 
    * @tparam t just for looks, and facilitate 
    * the implicit resolution scenario 
    */ 
    trait fo[t] { 
    /** 
    * An abstract type member THAT IS A TYPE CONSTRUCTOR 
    */ 
    type f[_] 
    } 

    // 
    // Types that will be used for `fo`'s abstract type `f[_]` 
    // 
    trait F1[t] 
    trait F2[t] 
    // 
    // Couple of case for type class `fo` 
    // 
    trait loo 
    implicit object loo extends loo with fo[loo] { 
    type f[t] = F1[t] 
    } 
    // 
    trait poo 
    implicit object poo extends poo with fo[poo] { 
    type f[t] = F2[t] 
    } 

    // Double checking, this compiles 
    val w0 = implicitly[ fo[loo] ] 
    val w1 = implicitly[ fo[poo] ] 

    /** 
    * *** PROBLEM HERE *** 
    * 
    * A method call, in which the abstract TYPE CONSTRUCTOR type member 
    * needs to be inferred by the compiler. 
    * 
    * This fails to be implicitly resolved, because the compiler 
    * fails to instantiate the type parameters, (probably) because 
    * it is unable to infer abstract type `f`. See further below 
    * for the failed invocation. 
    * 
    */ 
    def fu0[t, in[_]](t: t)(
    implicit 
    fo: fo[t] { type f[a] = in[a] } 
): String = s"Hi $t: $fo" 

    // These will work fine, since we explicitly set type param `in` 
    val w2 = fu0[loo, F1](loo: loo) 
    val w3 = fu0[poo, F2](poo: poo) 

    // *** PROBLEM HERE *** 
    // The following fails to compile 
    val w4 = fu0(loo: loo) // type ascription for test simplification 
    val w5 = fu0(poo: poo) // type ascription for test simplification 

    // 
    // Error message: 
    // 
    // (notice the "type f has one type parameter, but type in has one" 
    // part of the error) 
    // 
    // [info] .../incubator/Main.scala:64:15: poo is not a valid implicit value for incubator.wat.fo[incubator.wat.poo]{type f[a] = in[a]} because: 
    // [info] type parameters weren't correctly instantiated outside of the implicit tree: inferred kinds of the type arguments (incubator.wat.poo.f[t]) do not conform to the expected kinds of the type parameters (type in). 
    // [info] incubator.wat.poo.f[t]'s type parameters do not match type in's expected parameters: 
    // [info] type f has one type parameter, but type in has one 
    // [info] val w5 = fu0(poo: poo) // type ascription for test simplification 
    // [info]    ^
    // [info] .../incubator/Main.scala:64:15: incubator.this.wat.poo is not a valid implicit value for incubator.wat.fo[incubator.wat.poo]{type f[a] = in[a]} because: 
    // [info] type parameters weren't correctly instantiated outside of the implicit tree: inferred kinds of the type arguments (incubator.wat.poo.f[t]) do not conform to the expected kinds of the type parameters (type in). 
    // [info] incubator.wat.poo.f[t]'s type parameters do not match type in's expected parameters: 
    // [info] type f has one type parameter, but type in has one 
    // [info] val w5 = fu0(poo: poo) // type ascription for test simplification 
    // [info]    ^
    // [error] .../incubator/Main.scala:64:15: could not find implicit value for parameter fo: incubator.wat.fo[incubator.wat.poo]{type f[a] = in[a]} 
    // [error] val w5 = fu0(poo: poo) // type ascription for test simplification 
    // [error]    ^
    // [error] two errors found 
    // [error] (compile:compileIncremental) Compilation failed 
    // [error] Total time: 1 s, completed Oct 22, 2017 4:48:35 PM 
    // 

} 

答えて

0

fu0に次の定義を使用することによって、あなたは基本的にので、コンパイラが起こっている内容を正確に把握しないfoをリメイク。

implicit 
fo: fo[t] { type f[a] = in[a] } 

あなたはすでにfoを定義し、その静的な特性を使用することにより、あなたは明示的な型を使用する必要はありません。

def fu0[t, in[_]] 
    (t: t) 
    (implicit fo: fo[t]): String = s"Hi $t: $fo" 

実際のケースでは、この問題はネストされたタイプの方が深いと思われます。私の評価が正確であれば、もっと具体的なテストケースを用意して調べることができます。それはかなり面白い話題です。

再現

クリーンセットアップscalaVersion := "2.12.4"

package io.sosc 

object Main { 

    trait fo[t] { 

     type f[_] 
    } 

    trait F1[t] 
    trait F2[t] 

    trait loo 

    implicit object loo extends loo with fo[loo] { 
     type f[t] = F1[t] 
    } 

    trait poo 

    implicit object poo extends poo with fo[poo] { 
     type f[t] = F2[t] 
    } 

    def fu0[t, in[_]] 
     (t: t) 
     (implicit fo: fo[t]): String = s"Hi $t: $fo" 


    def main(args: Array[ String ]): Unit = { 



     val w0 = implicitly[ fo[loo] ] 
     val w1 = implicitly[ fo[poo] ] 

     val w2 = fu0[loo, F1](loo: loo) 
     val w3 = fu0[poo, F2](poo: poo) 

     println(w2) 
     println(w3) 

     val w4 = fu0(loo: loo) 
     val w5 = fu0(poo: poo) 

     println(w4) 
     println(w5) 
    } 
} 

結果:答えデニスのための

Hi [email protected]: [email protected] 
Hi [email protected]: [email protected] 
Hi [email protected]: [email protected] 
Hi [email protected]: [email protected] 
+0

おかげで、しかし、あなたはポイントをmenitonとして_ [におけるその型パラメータ 'であります] 'がメソッドのシグネチャで再利用されます。あなたのソリューションは、型変数をシグネチャから単に削除します。このユースケースを指定するには、その質問に明確化が必要です。再度、感謝します。 –

+0

包括的なテストケースを作成するときにコメントにタグを付けてください:) –