我希望计算两个列表的标量积。我们假设我们有两个列表l1 = List(1,2,3)
和l2 = List(4,5,6)
,结果应为List(4,10,18)
以下代码有效:
def scalarProduct(l1 : List[Int], l2 : List[Int]):List[Int] = {
val l3 = l1 zip(l2); l3 map(xy => xy._1*xy._2)
}
但是,以下内容无法编译,并说Cannot resolve reference map with such signature
:
def scalarProduct(l1 : List[Int], l2 : List[Int]):List[Int] = {
val l3 = l1 zip(l2); l3 map((x:Int,y:Int) => x*y)
}
这个zip()将返回一个Int对列表,上面的映射也采用了一个Int对的函数。 有人可以指出为什么第二种变体在这种情况下失败了吗?
答案 0 :(得分:15)
Your second example fails because you provide a function with 2 parameters to the map
, while map
takes a function with 1 parameter.
Have a look, here's a (simplified) signature of the map
function:
def map[B, That](f: A => B): That
The function f
is the one that you have to pass to do the conversion. As you can see, it has type A => B
, i.e. accept a single parameter.
Now take a look at the (simplified) zip function signature:
def zip [B](that : List[B]) : List[(A, B)]
It actually produces a list whose members are tuples. Tuple of 2 elements looks like this: (A, B)
. When you call map
on the list of tuples, you have to provide the function f
that takes a tuple of 2 elements as a parameter, exactly like you do in your first example.
Since it's inconvenient to work with tuples directly, you could extract values of tuple's members to a separate variables using pattern matching.
Here's an REPL session to illustrate this.
scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)
scala> List(2, 3, 4)
res1: List[Int] = List(2, 3, 4)
scala> res0 zip res1
res2: List[(Int, Int)] = List((1,2), (2,3), (3,4))
Here's how you do a standard tuple values extraction with pattern matching:
scala> res2.map(t => t match {
| case (x, y) => x * y
| })
res3: List[Int] = List(2, 6, 12)
It's important to note here that pattern matching expects a partial function as an argument. I.e. the following expression is actually a partial function:
{
case (x, y) => x * y
}
The partial function has its own type in Scala: trait PartialFunction[-A, +B] extends (A) => B
, and you could read more about it, for example, here.
Partial function is a normal function, since it extends (A) => B
, and that's why you can pass a partial function to the map
call:
scala> res2.map { case (x, y) => x * y }
res4: List[Int] = List(2, 6, 12)
You actually use special Scala syntax here, that allows for functions invocations (map
in our case) without parentheses around its parameters. You can alternatively write this with parentheses as follows:
scala> res2.map ({ case (x, y) => x * y })
res5: List[Int] = List(2, 6, 12)
There's no difference between the 2 last calls at all.
The fact that you don't have to declare a parameter of anonymous function you pass to the map
before you do pattern matching on it, is actually Scala's syntactic sugar. When you call res2.map { case (x, y) => x * y }
, what's really going on is pattern matching with partial function.
Hope this helps.
答案 1 :(得分:1)
你需要这样的东西:
def scalarProduct(l1 : List[Int], l2 : List[Int]):List[Int] = {
val l3 = l1 zip(l2); l3 map{ case (x:Int,y:Int) => x*y}
}
您可以查看this link来帮助解决此类问题。