将 apply 替换为运算符

Replace apply with operator

我有以下特点

trait Tr{
  def process(query: String)
}

object Tr{
  @inline def apply(implicit l: Tr): Tr = l
}

我想导入一些具有隐式值的对象并像这样调用它:

implicit val qpe: Tr = (i: String) => ()
val q: String = //some query
Tr.process(q)  //compile error
Tr.apply.process(q)  //OK!

但在 ScalaZ 中我们有以下对象:

object Functor {
  @inline def apply[F[_]](implicit F: Functor[F]): Functor[F] = F
  //...
}

和通话

Functor[List].lift((_: Int) + 3)

工作正常。有什么区别?

这个其实挺有意思的。看来诀窍是类型参数。当你这样做时

Tr.process(...)

它在 Tr 对象中查找名为 process 的方法,但找不到。这是搜索停止的地方。但是,Functor 采用类型参数。现在,单例对象不能有类型参数,所以当你写 Functor[List] 时,Scala 推断你只是 必须 调用 apply 方法并开始寻找暗示。可以通过向 Tr 对象的 apply.

添加虚拟类型参数来验证该理论
trait Tr[F] {
  def process(query: String)
}

object Tr {
  @inline def apply[F](implicit l: Tr[F]): Tr[F] = l
}

现在,当您尝试调用 Tr[Int].process(...) 时,您不可能单独引用对象 Tr,因为它不能有类型参数,因此 Scala 将其转换为Tr.apply[Int].process(...) 然后一切正常。

我不确定是否有办法在不强制类型参数的情况下获得隐式行为,并且显然不希望使用虚拟参数。但这似乎是您的代码与 Scalaz 的代码之间的区别。