关于隐式分辨率如何工作是否有任何好的来源,特别是关于类型推断和顺序(如果有的话)搜索所有隐含参数的implicits?
首先,我当然读过Scala语言规范,所以我理解(或者我认为)基础知识,比如编译器搜索implicits的地方。无论何时我尝试做一些更高级的事情,比如递归暗示,我总是遇到超自然的问题,并且与它们一起工作似乎是在尝试实验魔法。即使将所有隐含在一个伴随对象中并因此消除所有冲突的困难问题,代码中的一点变化(根据规范不应改变语义)有时会在编译和不编译之间产生差异。
我记得编译器找不到隐式Companion
的情况,但是在调用之前引入import Companion._
使其编译,而对象Companion只有隐式defs返回Companion实例。
我有一个代码以这种方式构建的案例:
object ADT {
class Evidence;
object Evidence {
class ParticularEvidence extends Evidence
object ParticularEvidence {
implicit def ... :ParticularEvidence
}
}
...
def f(...)(implicit e:ParticularEvidence) = ...
...
f(...)
没有编译,但是将特殊情况defs(UniqueEvidence中唯一的)从PRIVEvidence移动到父Evidence对象使它们可见。
经过一些试验和错误,我明白解决逻辑是非常有限的,并且构造了这个类,例如:
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的证据。更一般地说,我期望隐含的负[A,B,C]存在,当且仅当C是包含A的所有值而B的所有值的最小类型时。更重要的是,我希望即使C也能找到sch证据是未知的,只有来自A,B,所以我可以尝试实现隐式证据,允许自动将任何类型联合转换为某种规范化形式。最终,我想找到提供Normalized值的隐式方法的这种组合,我将能够编写如下内容:
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
因此,编译器在隐式方法强制执行的一组规则的帮助下,应该能够通过去除由其他部分支配的部分来简化联合类型。为此,我必须能够在类型上进行集合减法。
我知道我可能在这方面处于敌对的地位,任何编译器的改变都可能会破坏整个程序,但我将其视为一个谜题和概念证明。一旦我知道什么是可能的,我就会开始思考什么是明智的。
所以具体问题是:有没有人知道上面的代码究竟是什么问题,如果可以修复的话可以吗?
答案 0 :(得分:1)
编辑:我重写了这个答案,专注于Minus
:
我在减号中交换了隐式ConformsTo
规则。在nothing
和self
,您需要检查U ConformsTo C
。您应该在left
和right
:
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]
}
它允许您检查:
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]]