【发布时间】:2013-09-11 21:27:20
【问题描述】:
背景
我最近参加了一个初学者 Scala 聚会,我们正在讨论方法和函数之间的区别(也深入讨论了here)。
例如:
scala> val one = 1
one: Int = 1
scala> val addOne = (x: Int) => x + 1
addOne: Int => Int = <function1>
这表明 vals 不仅可以有整数类型,还可以有函数类型。我们可以在 scala repl 中看到类型:
scala> :type addOne
Int => Int
我们也可以在对象和类中定义方法:
scala> object Foo {
| def timesTwo(op: Int) = op * 2
| }
defined module Foo
虽然方法没有类型(而是有类型签名),但我们可以将其提升为函数以查看它是什么:
scala> :type Foo.timesTwo
<console>:9: error: missing arguments for method timesTwo in object Foo;
follow this method with `_' if you want to treat it as a partially applied function
Foo.timesTwo
^
scala> :type Foo.timesTwo _
Int => Int
到目前为止,一切都很好。我们甚至讨论了函数实际上是如何使用 apply 方法的对象,以及我们如何对表达式进行去语法糖化来展示这一点:
scala> Foo.timesTwo _ apply(4)
res0: Int = 8
scala> addOne.apply(3)
res1: Int = 4
对我来说,这对学习语言很有帮助,因为我可以内化语法的实际含义。
有问题的例子
但是,我们确实遇到了我们无法确定的情况。以字符串列表为例。我们可以将函数映射到演示基本 Scala 集合和函数式编程内容的值上:
scala> List(1,2,3).map(_*4)
res2: List[Int] = List(4, 8, 12)
好的,那么 List(1,2,3).map() 的类型是什么?我希望我们会在 repl 中做同样的 :type 技巧:
scala> :type List(1,2,3).map _
<console>:8: error: Cannot construct a collection of type Nothing with elements of type Nothing based on a collection of type List[Int].
List(1,2,3).map _
^
从 API 定义中,我知道签名是:
def map[B](f: (A) ⇒ B): List[B]
但也有完整的签名:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
问题
所以有两点我不太明白:
- 为什么普通函数提升技巧不适用于 List.map?有没有办法对错误陈述进行去语法糖化以证明发生了什么?
- 如果无法解除方法的原因是由于完整的签名“隐式”,那到底发生了什么?
最后,是否有一种可靠的方法来检查 REPL 中的类型和签名?
【问题讨论】:
-
关于隐式类型签名的问题在这里解释:stackoverflow.com/a/18533437/125901
标签: scala