这个“简单”ScalaZ教程代码示例中的隐式解析序列是什么?

时间:2014-11-02 10:28:36

标签: scala implicit-conversion implicit scalaz

下面的代码段摘自this ScalaZ教程。

在评估代码示例底部的10.truthy时,我无法弄清楚如何应用隐式解析规则。

我认为 - 我明白的事情如下:

1)隐式值intCanTruthyCanTruthy[A]的匿名子类的实例,它根据以下内容定义truthys的{​​{1}}方法:

Int

2)scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({ case 0 => false case _ => true }) intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051 隐式转换方法在评估toCanIsTruthyOps时属于范围,因此当编译器发现10.truthy没有{时,编译器将尝试使用此隐式转换方法{1}}方法。因此,编译器将尝试寻找一些隐式转换方法,该方法将Int转换为具有truthy方法的对象,因此它将尝试10进行此转换。

3)我怀疑当编译器在truthy上尝试toCanIsTruthyOps隐式转换时,可能会以某种方式使用隐式值intCanTruthy

但这是我真正迷失的地方。我只是没有看到隐含的解决方法过程如何进行。接下来发生什么 ?怎么样,为什么?

换句话说,我不知道什么是隐式解析序列,它允许编译器在评估toCanIsTruthyOps时找到10方法的实现。

问题

如何将truthy转换为具有正确10.truthy方法的某个对象?

那个对象是什么?

该对象来自哪里?

有人可以解释,详细,评估10时隐式解决方案是如何进行的?

truthy中的self-type 10.truthy如何在隐式解决过程中发挥作用?

{ self => ...

CanTruthy上试用类型类:

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait CanTruthy[A] { self =>
  /** @return true, if `a` is truthy. */
  def truthys(a: A): Boolean
}
object CanTruthy {
  def apply[A](implicit ev: CanTruthy[A]): CanTruthy[A] = ev
  def truthys[A](f: A => Boolean): CanTruthy[A] = new CanTruthy[A] {
    def truthys(a: A): Boolean = f(a)
  }
}
trait CanTruthyOps[A] {
  def self: A
  implicit def F: CanTruthy[A]
  final def truthy: Boolean = F.truthys(self)
}
object ToCanIsTruthyOps {
  implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A]) =
    new CanTruthyOps[A] {
      def self = v
      implicit def F: CanTruthy[A] = ev
    }
}

// Exiting paste mode, now interpreting.

defined trait CanTruthy
defined module CanTruthy
defined trait CanTruthyOps
defined module ToCanIsTruthyOps

2 个答案:

答案 0 :(得分:5)

首先,感谢您粘贴一个完全独立的示例。

  

如何将10转换为具有正确truthy方法的某个对象?

在类型A不提供该方法的值上调用方法时,必须启动隐式转换,即必须在带有签名的范围内有方法或函数{ {1}} A => B使用相关方法(B)。在转换方法的情况下,它可能会要求额外的隐式参数,这些参数将被相应地查找。

转化方法为truthy,可通过导入toCanIsTruthyOps的内容获得。上述句子中的ToCanIsTruthyOps类型为B,转换方法为CanTruthyOps。只要找到隐式类型类证据参数toCanIsTruthyOps,它就可以由编译器调用。因此,从CanTruthy开始,如果调用type A = Int将成功,编译器必须找到类型为CanTruthy[Int]的隐式值。

它在几个地方寻找这样的价值。它可能位于10.truthy的伴随对象(不存在)或Int的伴随对象中,或者显式导入当前范围。这里使用最后一种情况。您显式创建了隐式值CanTruthy,现在找到了该值。就是这样。

  

那个对象是什么?

将会有一个intCanTruthy的临时实例,其唯一目的是在证据类型类值(此处CanTruthyOps)上调用truthys

  

该对象来自哪里?

可以在查找隐式转化intCanTruthy时找到它。转换执行该对象的实例化。

  

有人可以详细解释在评估Int => CanTruthyOps[Int]时如何进行隐式解决吗?

见上面第一个问题的答案。或者作为显式代码:

10.truthy
  

type A = Int val v: A = 10 val ev: CanTruthy[A] = intCanTruthy val ops: CanTruthyOps[A] = ToCanIsTruthyOps.toCanIsTruthyOps(v)(ev) ops.truthy 中的自我类型{ self => ...如何在隐式解决过程中发挥作用?

它与隐式解决方案无关。实际上,在您CanTruthy的示例中,trait CanTruthy充当self的别名,甚至没有使用,因此您可以将其删除。

答案 1 :(得分:3)

A转换为具有CanTruthyOps[T]方法的truthy的方法的签名是:

implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A])

这意味着它不会仅转换任何A,而只会转换定义了CanTruthy[A]的{​​{1}},这是implicit ev参数的含义。这意味着,作为将10映射到具有.truthy方法的内容的过程的一部分,在包装完成之前也会查找intCanTruthy。因此,当10被隐式转换为具有truthy方法的内容时,intCanTruthy实例将已被查找并存储为F属性CanTruthyOps

implicit def F: CanTruthy[A] = ev

(实际上我不知道为什么那里需要implicit; truthy()会明确转向F

F.truthys(self)

至于隐式解决方案的工作原理,您最好查找详细描述该流程的文档。