2017-10-22 14 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

포괄적 인 테스트 케이스를 만들 때 주석에 나를 태그 지정하십시오 :) –