【问题标题】:What is the implicit resolution sequence in this "simple" ScalaZ tutorial code example?这个“简单”的 ScalaZ 教程代码示例中的隐式解析顺序是什么?
【发布时间】:2014-12-29 04:03:24
【问题描述】:

下面的代码sn-p取自thisScalaZ教程。

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

我认为我确实理解的事情如下:

1) 隐式值intCanTruthyCanTruthy[A] 的匿名子类的一个实例,它根据以下规定为Int-s 定义了truthys 方法:

scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
         case 0 => false
         case _ => true
       })
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051

2) 在评估10.truthy 时,toCanIsTruthyOps 隐式转换方法在作用域内,因此当编译器看到Int 没有truthy 方法时,它会尝试使用这种隐式转换方法。因此,编译器将尝试寻找一些隐式转换方法,将10 转换为具有truthy 方法的对象,因此它将尝试toCanIsTruthyOps 进行此转换。

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

但这是我真正迷路的地方。我只是看不到隐式解析过程在此之后如何进行。接下来发生什么 ?如何和为什么?

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

问题

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

那个对象是什么?

该对象将来自哪里?

有人可以详细解释,在评估10.truthy 时,隐式解析是如何发生的吗?

CanTruthy中的self-type{ self => ...是如何在隐式解析过程中发挥作用的?

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

10 上试用类型类:

scala> import ToCanIsTruthyOps._
import ToCanIsTruthyOps._

scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
         case 0 => false
         case _ => true
       })
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051

scala> 10.truthy
res6: Boolean = true

【问题讨论】:

    标签: scala implicit-conversion implicit scalaz


    【解决方案1】:

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

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

    当对类型A 不提供该方法的值调用方法时,必须进行隐式转换,即范围内必须有一个带有签名A => B 的方法或函数B 有问题的方法 (truthy)。在转换方法的情况下,它可能会要求额外的隐式参数,这些参数会被相应地查找。

    转换方式为toCanIsTruthyOps,导入ToCanIsTruthyOps的内容即可。那么上句中B的类型为CanTruthyOps,转换方式为toCanIsTruthyOps。只要找到隐式类型类证据参数CanTruthy,编译器就可以调用它。所以从type A = Int开始,如果调用10.truthy要成功,编译器必须找到CanTruthy[Int]类型的隐式值。

    它在多个地方寻找这样的值。它可能在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
    

    CanTruthy中的自我类型{ self => ...是如何在隐式解析过程中发挥作用的?

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

    【讨论】:

    • 非常感谢您提供详细而有价值的回答!
    • 为什么CanTruthyOps 的特征声明中的implicit def F: CanTruthy[A] 行中需要implicit 关键字?我看不出这里的隐含解决方案是如何需要的。 F 真的需要声明为隐式吗?
    • 这里完全不需要def F 的隐含。它可能在 Scalaz 的其他地方有一些用处。我知道这里看起来很混乱。忽略它。
    • 我从那里删除了隐式关键字,这个例子仍然可以编译,我得到了相同的结果。
    • 感谢您对此的确认。
    【解决方案2】:

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

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

    这意味着它不会转换任何A,而只会转换那些定义了CanTruthy[A] 的对象,这就是implicit ev 参数的用途。这意味着,作为将10 映射到具有.truthy 方法的对象的过程的一部分,在包装完成之前还要查找intCanTruthy。因此,当10 被隐式转换为具有truthy 方法的东西时,intCanTruthy 实例将已经被查找并存储为CanTruthyOpsF 属性:

    implicit def F: CanTruthy[A] = ev
    

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

    F.truthys(self)
    

    至于隐式解析的具体工作原理,您最好查找详细描述该过程的文档。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      • 2017-06-28
      • 1970-01-01
      • 1970-01-01
      • 2014-06-22
      相关资源
      最近更新 更多