2017-09-09 33 views
1

我想弄清楚为什么下面的Scala代码编译?斯卡拉函数接受不同类型

trait List[+A] 
case object Nil extends List[Nothing] 
case class Cons[+A](head: A, tail: List[A]) extends List[A] 

def map[A, B](as: List[A])(f: A => B): List[B] = as match { 
    case Nil   => Nil 
    case Cons(x, xs) => Cons(f(x), map(xs)(f)) 
} 

def tester[A, B](as: List[A])(f1: A => List[B]) = map(as)(f1) 

按我的理解,tester不应该编译,因为map定义说,它接受两个参数:一个名单列表A => B类型的函数。

然而,在tester功能我有功能f1这是A => List[B]类型,因此,作为参数不匹配的类型,我认为编译器应该抛出错误。但代码编译正常。

你能帮我理解为什么代码在这里编译?

+0

'.map'应该声明的类型参数'A',否则此人会影在该性状的水平类型参数'A'(并且在这种情况下无用反正) – cchantep

+0

@cchantep'map'是特质之外。 – HTNW

回答

2

tester[A,B]方法中,您实际上正在调用map[A, List[B]]

如果您使用不同的类型参数编写测试仪方法,那么可能代码更易于理解,然后调用map,A = CB = List[D]

def tester[C, D](as: List[C])(f1: C => List[D]): List[List[D]] = { 
    map[C, List[D]](as)(f1) 
} 
+0

感谢您的回复。我实际上忘了Scala编译器从传递的参数中推断参数的类型。我怎么仍然不明白为什么在测试仪方法中地图实际上是地图[A,列表[B]]?由于列表[A]的类型和f1的类型是A =>列表[B]。那么地图应该不是地图[列表[A],A =>列表[B]]? – Somenath

+0

@Somenath编译器推断映射的类型参数,使得调用中的参数'as'和'f'是兼容的。由于'f1:A =>列表[B]','map'必须是'map [A​​,List [B]]' – Harald

1

我觉得你的误解来自于事实,你假设AB类型是共同的maptester,而他们实际上是本地定义。为了本示例的目的,我们将testerB重命名为C。这意味着的map实际上是List[C]