是否有任何关于隐式解析如何工作的好资料,特别是关于在其中搜索所有隐式参数的类型推断和顺序(如果有)?
首先,我当然阅读了 Scala 语言规范,所以我理解(或者我认为)基础知识,比如编译器在哪里搜索隐式。然而,每当我尝试做一些更高级的事情时,比如递归隐式,我总是会遇到超自然的问题,与它们一起工作就像是在练习实验魔法。即使将所有隐式保存在一个伴生对象中,从而消除所有与冲突有关的困难问题,代码中的一些更改(不应该根据规范更改语义)有时会在编译和不编译之间产生差异。
我记得编译器找不到隐式 for 的情况Companion
,但import Companion._
在调用之前引入使其编译,并且 object Companion 只有隐式 defs 返回 Companion 实例。
我有一个这样的代码结构的案例:
object ADT {
class Evidence;
object Evidence {
class ParticularEvidence extends Evidence
object ParticularEvidence {
implicit def ... :ParticularEvidence
}
}
...
def f(...)(implicit e:ParticularEvidence) = ...
...
f(...)
没有编译,但是将隐含定义(ParticularEvidence 的唯一定义)从 ParticularEvidence 移动到父 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] 基本上是一种美化的 Either,具有透明的结构扁平化和隐藏的左/右选项)。减号是我想要实现的类型算术的一部分:在最后一行中,我要求编译器提供 SA||SB - Nothing = SA||SB 的证据。更一般地说,当且仅当 C 是包含来自 A 的所有值且没有 B 值的最小类型时,我希望存在隐式减号 [A,B,C]。此外,我希望它能够找到 sch 证据,即使 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
因此,编译器在隐式方法强制执行的规则集的帮助下,应该能够通过摆脱由其他部分支配的部分来简化联合类型。为此,我必须能够对类型进行集合减法。
我知道我可能在这个敌人的领土上很远,任何编译器更改都可能会因此而破坏整个程序,但我主要将其视为一个谜题和概念证明。一旦我知道什么是可能的,我就会开始思考什么是明智的。
所以具体的问题是:有没有人知道上面的代码到底出了什么问题,如果可以修复它可以吗?