通常在Scala文献中,我遇到了"抽象结束"这个短语,但我不明白其意图. 例如,马丁奥德斯基写道
您可以将方法(或"函数")作为参数传递,也可以对它们进行抽象.您可以将类型指定为参数,也可以对它们进行抽象.
另一个例子,在"弃用观察者模式"一文中,
我们的事件流是第一类值的结果是我们可以抽象它们.
我已经读过第一阶泛型"抽象类型",而monads"抽象类型构造函数".我们还在Cake Pattern论文中看到了这样的短语.引用许多这样的例子中的一个:
抽象类型成员提供了抽象的具体类型的组件的灵活方式.
即使相关的堆栈溢出问题也使用此术语. "不能存在抽象的参数化类型..."
所以......"抽象"究竟意味着什么?
在Scala中,我可以使用两个参数列表定义一个函数.
def myAdd(x :Int)(y :Int) = x + y
Run Code Online (Sandbox Code Playgroud)
这样可以轻松定义部分应用的功能.
val plusFive = myAdd(5) _
Run Code Online (Sandbox Code Playgroud)
但是,我可以通过定义和返回嵌套函数来完成类似的事情.
def myOtherAdd(x :Int) = {
def f(y :Int) = x + y
f _
}
Run Code Online (Sandbox Code Playgroud)
在化妆方面,我已经移动了下划线,但这仍然感觉像是在晃动.
val otherPlusFive = myOtherAdd(5)
Run Code Online (Sandbox Code Playgroud)
我应该使用什么标准来偏好一种方法呢?
假设我有一个包装整数的简单case类,以及一个接受带有整数到包装器的函数的高阶方法.
case class Wrapper(x :Int)
def higherOrder(f : Int => Wrapper) = println(f(42))
Run Code Online (Sandbox Code Playgroud)
然后,我可以调用高阶函数,传入包装器生成的apply函数.令人惊讶的是,我也可以传递包装器的名称.
higherOrder(Wrapper.apply) // okay
higherOrder(Wrapper) // okay, wow!
Run Code Online (Sandbox Code Playgroud)
这真的很酷.它允许我们将case类的名称视为一个函数,它可以促进表达式抽象.有关这种凉爽的一个例子,请参阅这里的答案. "抽象"是什么意思?
现在假设我的case类不够强大,我需要创建一个提取器.作为一个有点人为的用例,假设我需要能够对解析为整数的字符串进行模式匹配.
// Replace Wrapper case class with an extractor
object Wrapper {
def apply(x :Int) = new Wrapper(x)
def unapply(s :String) :Option[Wrapper] = {
// details elided
}
}
class Wrapper(x :Int) {
override def toString = "Wrapper(" + x + ")"
// other methods elided
}
Run Code Online (Sandbox Code Playgroud)
在这个变化下,我仍然可以将Wrapper.apply传递给我的高阶函数,但是传入Wrapper不再有效.
higherOrder(Wrapper.apply) // still okay
higherOrder(Wrapper) // DOES NOT COMPILE …Run Code Online (Sandbox Code Playgroud)