2014-10-14 1 views
0

암시 적 해석이 작동하는 방법, 특히 모든 암시 적 매개 변수에 대한 암시가 검색되는 형식 유추 및 순서 (있는 경우)와 관련하여 좋은 출처가 있습니까?암시 적 해상도 및 해당 매개 변수 형식 추론이

처음에는 물론 Scala Language Specification을 읽었으므로 컴파일러가 implicits를 검색하는 위치와 같은 기본 사항을 이해하고 있습니다. 그러나 재귀 적 함축과 같이 좀 더 진보 된 것을하려고 할 때마다 나는 항상 초자연적 인 문제에 직면하게되고, 실험적인 마술처럼 진부 해 보인다. 모든 implicits를 companion 오브젝트에 포함 시켜서 충돌로 인한 모든 어려운 문제를 제거하더라도 스펙에 따라 시맨틱을 변경하지 않아야하는 코드의 약간의 변경은 때때로 컴파일하는 것과 컴파일하지 않는 것 사이의 차이를 만듭니다.

컴파일러가 Companion에 대해 암시 적으로 찾지 못했지만 호출하기 전에 import Companion._을 도입하면 오브젝트 컴패니언에 컴패니언 인스턴스를 반환하는 암시 적 def 만있었습니다.

나는 코드가 이런 식으로 구조화 된 사건이 ​​있었다 :

object ADT { 

class Evidence; 
object Evidence { 
    class ParticularEvidence extends Evidence 
    object ParticularEvidence { 
     implicit def ... :ParticularEvidence 
    } 
} 
... 
def f(...)(implicit e:ParticularEvidence) = ... 
... 
f(...) 

컴파일하지 않았다, 그러나 부모 증거 객체에 ParticularEvidence에서 implicits의 인증 된 정의 (ParticularEvidence에 대한 유일한 사람)를 이동하는 그들을 볼 수했다.

약간의 시행 착오 후에 나는 해상도 논리가 매우 제한되어 있으며, 예를 들어,이 클래스의 구조 있음을 이해 :

implicit def f[X, Y, Z](x :X)(implicit e1:Evidence1[X, Y], implicit e2:Evidence[Y, Z]) :Y 
... 
val x :X = ... 
val z:Z = x 
증거 클래스가 정확히 하나가 있다면 거의 심지어 컴파일되지 않습니다 자신의 유형 매개 변수에 불변

그러한 암시 적 값이 존재하는 타입 Z. 다음이 문제가 왜하지만 난 아무 생각이 :

/** Stub for the purpose of this example **/ 
sealed abstract class ||[+A,+B] 
case class LeftVariant[+A](left :A) extends ||[A, Nothing] 
case class RightVariant[+B](right :B) extends ||[Nothing, B] 


object SupportingEvidence { 

    /** C is an Atom and U==C or U is a type union explicitly containg C */ 
    sealed class ComponentOf[C, U] protected[SupportingEvidence]() extends SupportingEvidence 

    final class Atom[T] protected[SupportingEvidence]() extends ComponentOf[T, T] 

    implicit def atom[T](implicit ev :Not[T <:< ||[_,_]]) = a.asInstanceOf[Atom[T]] 

    implicit def leftComponent[A, B, C](implicit ev: C ComponentOf A): C ComponentOf (A || B) = 
     ev.asInstanceOf[ComponentOf[C, A || B]] 

    implicit def rightComponent[A, B, C](implicit ev: C ComponentOf B, but: Not[C ComponentOf A]): C ComponentOf (A || B) = 
     ev.asInstanceOf[ComponentOf[C, A || B]] 

    private[this] val a = new Atom[Nothing] 


    type Something[X] = Not[X<:<Nothing] 


    /** T = U - C, calculated as follows: 
     * U = A || B => A - C || B - C 
     * U <: C => Nothing 
     * else => U 
     */ 
    final class Minus[U, C, T] protected[SupportingEvidence]() extends SupportingEvidence 

    object Minus { 
     implicit def nothing[U, C](implicit atom :Atom[U], conforms :U ConformsTo C) :Minus[U, C, Nothing] = 
      certify[U, C, Nothing] 

     implicit def self[U, C](implicit atom :Atom[U], diff :Not[U ConformsTo C]) :Minus[U, C, U] = 
      certify[U, C, U] 

     implicit def left[A, B, C, T](implicit left :Minus[A, C, T], 
             leftSomething :Not[C ConformsTo A], 
             rightNothing :C ConformsTo B) :Minus[A || B, C, T] = 
      certify[A || B, C, T] 

     implicit def right[A, B, C, T](implicit leftNothing :C ConformsTo A, 
             right :Minus[B, C, T]) :Minus[A || B, C, T] = 
      certify[A || B, C, T] 

     implicit def union[A, B, C, L, R](implicit atom :Atom[C], 
              leftSomething :Not[C ConformsTo A], 
              rightSomething :Not[C ConformsTo B], 
              left :Minus[A, C, L], 
              right :Minus[B, C, R]) :Minus[A || B, C, L || R] = 
      certify[A || B, C, L || R] 

     private[this] def certify[U, C, T] = m.asInstanceOf[Minus[U, C, T]] 

    } 

    private[this] val m = new Minus[Nothing, Nothing, Nothing] 
} 



final class ConformsTo[-X, +Y] protected[ADT] (protected[ADT] val cast :X=>Y) //extends Conversion[X, Y] 

object ConformsTo { 
    import SupportingEvidence._ 

    private def apply[X, Y](fun :X=>Y) :ConformsTo[X, Y] = new ConformsTo(fun) 

    implicit def directlyConformsTo[X, Y](implicit ev :X <:< Y) :ConformsTo[X, Y] = 
     ConformsTo(ev.apply _) 

    implicit def conformsToLeft[X, A, B](implicit atom :Atom[X], 
             conform :ConformsTo[X, A], 
             only :Not[ConformsTo[X, B]]) :ConformsTo[X, A || B] = 
     ConformsTo((x :X) => LeftVariant(conform.cast(x))) 

    implicit def conformsToRight[X, A, B](implicit atom :Atom[X], 
              conform :ConformsTo[X, B], 
              only :Not[ConformsTo[X, A]]) :ConformsTo[X, A || B] = 
     ConformsTo((x :X) => RightVariant(conform.cast(x))) 

    implicit def conformsToBoth[X, A, B](implicit atom :Atom[X], 
             left :ConformsTo[X, A], 
             right :ConformsTo[X, B]) :ConformsTo[X, A || B] = 
     ConformsTo((x :X) => LeftVariant(left.cast(x))) 

    implicit def alternativesConform[A, B, Y](implicit left :ConformsTo[A, Y], right :ConformsTo[B, Y], 
               nonDirect :Not[(A || B) <:< Y]) :ConformsTo[A || B, Y] = 
     ConformsTo((x :A || B) => x match { 
      case LeftVariant(l) => left.cast(l) 
      case RightVariant(r) => right.cast(r) 
     }) 

} 
} 

/** Implicit value for Not[T] exists <=> there's no implicit value for T in scope */ 
final class Not[+T](override val toString :String) 

object Not { 
    private[this] val nice = new Not[Nothing]("default") 
    private[this] val mean = new Not[Nothing]("conflict") 

    implicit def conflict[T](implicit ev :T) :Not[T] = mean 
    implicit def default[T] :Not[T] = nice 
} 

//test Minus 
class SA 
class SB 
implicitly[Minus[SA || SB, Nothing, SA || SB]] //unhelpful divergent expansion error 

내가 (|| 박스 타입의 조합으로 여기에 실험하고 [A는 B] 기본적으로 구조의 평탄화 투명와 왼쪽 숨겨진 어느 영광입니다/올바른 옵션). 빼기는 구현하려는 유형 연산의 일부입니다. 마지막 줄에서 컴파일러가 SA || SB - Nothing = SA || SB를 제공해야한다고 요구합니다. 더 일반적으로 C가 A의 모든 값과 B의 값을 모두 포함하는 가장 작은 유형 인 경우에만 암시적인 마이너스 [A, B, C]가 존재할 것으로 기대합니다. 알 수없는 경우에만 A, B에서만 가능하므로 암시적인 증거를 구현하여 모든 형식화 된 유니온을 정규화 된 형식으로 자동 변환 할 수 있습니다. 암시 적 방법에 의해 시행 규칙 세트의 도움으로,

def normalize[A,B,N](v :A || B)(implicit :Normalized[A || B, N]) :N 
val a :Int || java.sql.Date || Int || String || java.lang.Date = ... 
val n = normalize(a) //n is of type Int || java.lang.Date || String 

그래서 컴파일러한다 : 결국, 나는 이런 식으로 뭔가를 쓸 수있을 것입니다, 정규화 된 값을 제공 암시 적 방법 등의 조합을 찾으려면 다른 부분이 지배하는 부분을 없앰으로써 노동 조합 유형을 단순화 할 수 있습니다. 이를 위해 유형에 대해 빼기를 설정할 수 있어야합니다.

나는 아마도 이것으로 적의 teritory에 있고 모든 컴파일러 변경이 이것에 따라 전체 프로그램을 망가뜨릴 수도 있음을 알고 있지만, 주로 퍼즐과 개념 증명으로 간주합니다. 일단 내가 무엇이 가능한지 알게되면, 나는 합리적인 것을 생각하기 시작할 것입니다.

그래서 구체적인 질문입니다 : 위의 코드가 정확히 무엇인지 정확히 아는 사람이 누구인지 알 수 있습니까?

+3

귀하의 질문은 무엇인가 :

final class Minus[U, C, T] extends SupportingEvidence object Minus { implicit def nothing[U, C](implicit atom: Atom[U], conforms: U ConformsTo C): Minus[U, C, Nothing] = certify[U, C, Nothing] implicit def self[U, C](implicit atom: Atom[U], diff: Not[U ConformsTo C]): Minus[U, C, U] = certify[U, C, U] implicit def left[A, B, C, T](implicit left: Minus[A, C, T], leftSomething: Not[A ConformsTo C], rightNothing: B ConformsTo C): Minus[A || B, C, T] = certify[A || B, C, T] implicit def right[A, B, C, T](implicit leftNothing: A ConformsTo C, right: Minus[B, C, T]): Minus[A || B, C, T] = certify[A || B, C, T] implicit def union[A, B, C, L, R](implicit //atom: Atom[C], leftSomething: Not[A ConformsTo C], rightSomething: Not[B ConformsTo C], left: Minus[A, C, L], right: Minus[B, C, R]): Minus[A || B, C, L || R] = certify[A || B, C, L || R] def certify[U, C, T] = nothingMinusNothingIsNothing.asInstanceOf[Minus[U, C, T]] val nothingMinusNothingIsNothing = new Minus[Nothing, Nothing, Nothing] } 

그것은 당신이 확인할 수 있습니다? – gwenzek

+0

aargh, 미안 해요, 화재 훈련이 나를 방해하고 나는 질문을 요약하는 것을 잊어 버렸습니다. 1. 아무도 위의 컴파일을 할 수 있습니까? 2. 어떤 작품에 대해 읽을 수있는 출처가 있습니까, 어떻게 작동하며, 반년 이내에 여전히 작동 할 수있는 기회는 무엇입니까? – Turin

+1

코드 샘플이 불완전합니다. 아니면 코드가 없음을 나타내는 타원을 의미합니까? –

답변

1

편집 :

내가 마이너스에서 암시 적 ConformsTo 규칙을 교환 : 나는 Minus에 초점이 답을 다시 썼다. nothingselfU ConformsTo C을 확인하십시오. 당신은 leftright에서 동일한 작업을 수행해야합니다

trait Animal 
trait Car 
trait Cow extends Animal 
trait Barking 
class Dog extends Animal with Barking 

implicitly[Minus[Dog, Animal, Nothing]] 
implicitly[Minus[Dog, Barking, Nothing]] 
implicitly[Minus[Cow, Barking, Cow]] 
implicitly[Minus[Cow, Animal with Barking, Cow]] 

implicitly[Minus[Dog || Cow, Barking, Cow]] 
implicitly[Minus[Cow || Dog, Barking, Cow]] 
implicitly[Minus[Cow || Car, Barking, Cow || Car]]  
+0

https://gist.github.com/gwenzek/123fc48c83d3da9a0fda 자세한 내용은 – gwenzek

+0

노력에 감사 드리며, 나는 내일 일할 것입니다. 마이너스가 일하니? ComponentOf 및 ConformsTo가 나를 위해 일했습니다. javadocs에서와 같이 목표는 값 집합으로 간주되는 유형에 산술을 제공하는 것이었고 Minus [A, B, C] C는 A의 모든 값과 B 값이없는 가장 작은 유형입니다. 암시 적으로 [Minus [A, A, Nothing]] 그리고 암시 적으로 [마이너스 [A, Nothing, A]] 컴파일하지만 마이너스 [A || B, Nothing, A || B]는 컴파일하지 않습니다. 나는 컴파일러가 A, B가 암시 적으로 검색하고 Normalized의 구현에서 추론 된 유형을 사용하여 알 때 Minus [A, B, C]에서 유형 C를 추론하도록 만들려고했습니다. – Turin

+0

가장 느슨한 의미에서 '최소', C1, ..., C2의 순열 중 하나 인 C = C1 || ... || C2. 암묵적인 값이 그러한 순열에 대해서만 존재하는 한, 나는 그걸로 충분하다. 따라서 정규화 된 [Int || String, Int || String], 정규화 된 [String || Int, String || Int] - 두 번째 유형 매개 변수는 아마 다를 것입니다. , 그들은 진정한 정규화에서 동일해야합니다. 내가 런타임에 확인할 수있는 유형에 대한 완전한 순서를 소개하는 방법을 모르겠다. – Turin

관련 문제