암시 적 해석이 작동하는 방법, 특히 모든 암시 적 매개 변수에 대한 암시가 검색되는 형식 유추 및 순서 (있는 경우)와 관련하여 좋은 출처가 있습니까?암시 적 해상도 및 해당 매개 변수 형식 추론이
처음에는 물론 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에 있고 모든 컴파일러 변경이 이것에 따라 전체 프로그램을 망가뜨릴 수도 있음을 알고 있지만, 주로 퍼즐과 개념 증명으로 간주합니다. 일단 내가 무엇이 가능한지 알게되면, 나는 합리적인 것을 생각하기 시작할 것입니다.
그래서 구체적인 질문입니다 : 위의 코드가 정확히 무엇인지 정확히 아는 사람이 누구인지 알 수 있습니까?
귀하의 질문은 무엇인가 :
이그것은 당신이 확인할 수 있습니다? – gwenzek
aargh, 미안 해요, 화재 훈련이 나를 방해하고 나는 질문을 요약하는 것을 잊어 버렸습니다. 1. 아무도 위의 컴파일을 할 수 있습니까? 2. 어떤 작품에 대해 읽을 수있는 출처가 있습니까, 어떻게 작동하며, 반년 이내에 여전히 작동 할 수있는 기회는 무엇입니까? – Turin
코드 샘플이 불완전합니다. 아니면 코드가 없음을 나타내는 타원을 의미합니까? –