2014-08-31 41 views
3

我看了一下scalaz tutorialAd-hoc多态 - 类型

this link,我明白下面的代码:

scala> def sum[A](xs: List[A])(implicit m: Monoid[A]): A = xs.foldLeft(m.mzero)(m.mappend) 
sum: [A](xs: List[A])(implicit m: Monoid[A])A 

scala> implicit val intMonoid = IntMonoid 
intMonoid: IntMonoid.type = [email protected] 

scala> sum(List(1, 2, 3, 4)) 
res9: Int = 10 

但我不明白下面的代码:

scala> def sum[A: Monoid](xs: List[A]): A = { 
     val m = implicitly[Monoid[A]] 
     xs.foldLeft(m.mzero)(m.mappend) 
     } 
sum: [A](xs: List[A])(implicit evidence$1: Monoid[A])A 

scala> sum(List(1, 2, 3, 4)) 
res10: Int = 10 

如果我们考虑List(1, 2, 3, 4)AInt

那么我们怎样才能有AMonoidAIntdef sum[A: Monoid](xs: List[A]): A = {

谢谢

回答

6

语法A : X被称为“绑定上下文”,它是等效于接收所述类型X[A]的隐式参数。也就是说,以下两个声明是一样的:

def sum[A: Monoid](xs: List[A]): A 
def sum[A](xs: List[A])(implicit $ev0: Monoid[A]): A 

但是,使用上下文范围时,那么你需要的,如果你需要直接用它来“检索”,它的隐含参数的名称是不可用。要做到这一点的方法之一是使用implicitly方法,如:

val m = implicitly[Monoid[A]] 

这里是implicitly定义:

def implicitly[T](implicit v: T): T = v 

反正你已经证明了两个定义是大同小异的。如果你理解第一个,只要知道第二个是相同的,但是用不同的语法编写。

关于上下文边界的最后一点注意事项:使用上下文绑定语法只是后来使用implicitly来获取参数的名称似乎很愚蠢。但是,如果你只是需要将隐式参数作为隐式传递给其他方法 - 因此不需要知道名称 - ,它会使声明更加整齐。