使Scala的implicitNotFound注释更精确
我在
Scala中遇到了类型类的问题,更准确地说,在编译时无法找到类型类实例时出现错误.假设我有一个类型类TC和一个对象B [C],只有当C有一个TC实例时才有一个TC实例.在Scala中,这可以写成隐式def btc [C](隐式ctc:TC [C])= new TC [B [C]] {…}.当你需要TC的一个TC [B [C]],scalac找不到实例TC [C]时,scalac会给出一个错误,说它找不到TC [B [C]].虽然这是真的,但是错误消息缺少scalac无法找到TC [B [C]]的原因,即它无法找到TC [C].
为了说明这个问题,我决定制作一个小玩具示例,其中TC为PrettyPrintable,C为Unit,B为选项: import scala.annotation.implicitNotFound @implicitNotFound("Cannot pretty print instances of the type ${T}") trait PrettyPrintable[T] { def prettyPrint(t: T): String } object PrettyPrintable { def apply[T](implicit pp: PrettyPrintable[T]): PrettyPrintable[T] = pp implicit def optPP[T](implicit opp: PrettyPrintable[T]) = new PrettyPrintable[Option[T]] { override def prettyPrint(ot: Option[T]): String = ot.fold("")(opp.prettyPrint) } } object Main extends App { println(PrettyPrintable[Option[Unit]].prettyPrint(None)) // error } 如果我运行该应用程序,我收到错误: [error] /home/rief/prog/scala/implicitNotFoundTest/Main.scala:24: Cannot pretty print instances of the type Option[Unit] [error] println(PrettyPrintable[Option[Unit]].prettyPrint(None)) 这当然是正确的:scalac找不到类型为Option [Unit]的漂亮的打印实例.问题是错误本身并不是很有用,因为重点不在于scalac找不到类型类的实例,而是找不到它的原因.在这种情况下,Option [Unit]没有漂亮的打印实例的原因是因为Unit没有漂亮的打印实例,但对于更复杂的情况,这可能是一场噩梦. 我的问题是:是否有可能使隐含的错误更加精确? 解决方法
那会很好,但我认为你想要解决的问题比初看起来时要复杂得多.在这个例子中,我为PrettyPrintable添加了一些更隐式的val和defs:
import scala.annotation.implicitNotFound @implicitNotFound("Cannot pretty print instances of the type ${T}") trait PrettyPrintable[T] { def prettyPrint(t: T): String } object PrettyPrintable { def apply[T](implicit pp: PrettyPrintable[T]): PrettyPrintable[T] = pp implicit val intPP = new PrettyPrintable[Int] { override def prettyPrint(i: Int): String = s"== $i ==" } implicit def optPP[T](implicit opp: PrettyPrintable[T]) = new PrettyPrintable[Option[T]] { override def prettyPrint(ot: Option[T]): String = s"-- ${ot.map(opp.prettyPrint)} --" } implicit def pairPP[T,U](implicit tpp: PrettyPrintable[T],upp: PrettyPrintable[U]) = new PrettyPrintable[(T,U)] { override def prettyPrint(pair: (T,U)): String = s"[[[ ${tpp.prettyPrint(pair._1)} >>> ${upp.prettyPrint(pair._2)} ]]]" } } object Main extends App { println(PrettyPrintable[Int].prettyPrint(6)) // prints == 6 == println(PrettyPrintable[Option[Int]].prettyPrint(None)) // prints -- None -- println(PrettyPrintable[Option[Int]].prettyPrint(Some(6))) // prints -- Some(== 6 ==) -- println(PrettyPrintable[(Int,Int)].prettyPrint((6 -> 7))) // prints [[[ == 6 == >>> == 7 == ]]] println(PrettyPrintable[(Float,Long)].prettyPrint((6F -> 7L))) // error } 最后一行产生以下编译器错误,类似于示例中的错误: Cannot pretty print instances of the type (Float,Long) 在你的情况下,很容易因未找到隐含的PrettyPrintable [Unit]而找不到隐含的PrettyPrintable [Option [Unit]].但是对于这对,你想要责备没有找到隐含的PrettyPrintable [(Float,Long)]没有找到隐含的PrettyPrintable [Float],没有找到隐含的PrettyPrintable [Long],或两者兼而有之? 请注意,隐式解析失败的根本原因甚至可能与原始解析失败的形状不同.例如,考虑添加以下两个隐式defs: implicit def i2ppf(implicit i: Int) = new PrettyPrintable[Float] { override def prettyPrint(f: Float): String = s"xx $f xx" } implicit def s2ppf(implicit s: String) = new PrettyPrintable[Float] { override def prettyPrint(f: Float): String = s"xx $f xx" } 现在,根本原因是找不到隐式Int,还是找不到隐式String?实际答案非常复杂.像这样的东西: >没有隐含的PrettyPrintable [(Float,Long)]因为: >对于那种精确类型,AND没有隐含的值 > PrettyPrintable [Float]没有暗示,因为: >对于那种精确类型,AND没有隐含的值 > PrettyPrintable [Long]没有隐含的原因,因为: >该精确类型没有隐含值 在回答你的问题时,“是否有可能使隐含的错误更加精确?”,我认为这将涉及为您提供某种程序化访问,以便您更准确地构造错误消息.一般情况.只为这项工作设计一个不错的API将是一项非常令人印象深刻的工作,更不用说该API的实现了. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |