为什么方法参数F与类型构造函数F具有相同的名称?

时间:2019-12-03 18:04:36

标签: scala functional-programming typeclass

我正在观看John De Goes的“ FP to the Max”视频。在代码中,他做了这样的事情来获取隐式对象:

  object Program {
    def apply[F[_]](implicit F: Program[F]): Program[F] = F
  }

这是否意味着变量名F(implicit F: Program[F]中的第一个)实际上是一个不同的F?这很令人困惑。他是否打算这样做:

  object Program {
    def apply[F[_]](implicit ev: Program[F]): Program[F] = ev
  }

在返回F时,编译器如何知道他指的是哪个F?类型构造函数还是作用域中的变量?

2 个答案:

答案 0 :(得分:4)

例如,函数参数T与类型参数T不同

def f[T](T: T): T = T
f(42) // res0: Int = 42

编译器不会感到困惑,因为来自类型different universe中存在

  

...存在两个独立的宇宙,类型宇宙和   价值宇宙。在价值的宇宙中,我们有一些方法可以   将值作为圆括号中的参数(或偶尔卷曲)   大括号)。在类型的世界中,我们有类型构造函数,它接受类型   作为方括号中的参数。

在处理类型类时有时会使用此约定。这意味着我们只想返回解析为F的typeclass实例。为避免混淆,您可以使用您已经提出的ev方法,甚至

object Program {
  def apply[F[_]: Program]: Program[F] = implicitly[Program[F]]
}

作为附带说明,在类型类的伴随对象中使用apply方法的这种技巧使我们避免了必须使用implicitly的情况,例如给定的

trait Foo[T]
trait Bar[T]

trait Program[F[_]]
implicit val fooProgram: Program[Foo] = ???
implicit val barProgram: Program[Bar] = ???

object Program {
  def apply[F[_]: Program]: Program[F] = implicitly
}

然后我们可以写

Program[Bar]

代替

implicitly[Program[Bar]]

答案 1 :(得分:3)

  

在返回F时,编译器如何知道他指的是哪个F?类型构造函数还是作用域中的变量?

编译器知道方法/函数只能返回一个值。因此,=之后的类型是 ,而不是