scala - 为什么我不能只对 Scala 中的第一个参数应用下划线?
问题描述
我不知道为什么模式 d 在下面的列表中不好。为什么需要显式类型声明?
def adder1(m:Int,n:Int) = m + n
val a = adder1(2,_) //OK
val b = adder1(_,2) //OK
def adder2(m:Int)(n:Int) = m + n
val c = adder2(2)(_) //OK
val d = adder2(_)(2) //NG:missing parameter type
val e = adder2(_:Int)(2) //OK
我只想知道为什么模式 d 需要参数类型。非常欢迎仅显示引用语言规范。
解决方案
所以我相信这来自Partial Application的概念。
直观地说,部分函数应用程序说“如果你修复函数的第一个参数,你会得到一个剩余参数的函数”
...
Scala 使用占位符实现可选的部分应用程序,例如
def add(x: Int, y: Int) = {x+y}; add(1, _: Int)
返回一个递增函数。Scala 还支持多个参数列表作为 currying,例如def add(x: Int)(y: Int) = {x+y}; add(1) _
.
让我们来看看adder2
来自 REPL:
scala> def adder2(m:Int)(n:Int) = m + n
def adder2(m: Int)(n: Int): Int
让我们得到一个值来表示:
scala> val adder2Value = adder2
^
error: missing argument list for method adder2
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `adder2 _` or `adder2(_)(_)` instead of `adder2`.
好的,让我们试试:
val adder2Value = adder2 _
val adder2Value: Int => (Int => Int) = $Lambda$1382/0x0000000840703840@4b66a923
啊哈!
英文:“一个接受一个Int
并返回一个函数的函数,一个接受一个Int
并返回一个Int
”
我们如何使用这个签名绑定第二个参数?除非我们首先通过外部函数,否则我们如何访问内部函数?
据我所知,除非您明确定义第一个参数的类型,否则使用此签名是不可能的。
(但是呢adder2(_)(_)
?)
scala> adder2(_)(_)
^
error: missing parameter type for expanded function ((<x$1: error>, x$2) => adder2(x$1)(x$2))
^
error: missing parameter type for expanded function ((<x$1: error>, <x$2: error>) => adder2(x$1)(x$2))
(也许这暗示了我们的解决方案?)
注意如果我们明确定义两个参数会发生什么:
val adder2Value2= adder2Value (_:Int) (_:Int)
val adder2Value2: (Int, Int) => Int = $Lambda$1394/0x000000084070d840@32f7d983
这更易于管理,我们现在可以修复任一参数,并获得简化的偏函数:
scala> val adder2FirstArg = adder2Value (_:Int) (10)
val adder2FirstArg: Int => Int = $Lambda$1395/0x000000084070d040@47f5ddf4
scala> val adder2SecondArg = adder2Value (5) (_:Int)
val adder2SecondArg: Int => Int = $Lambda$1396/0x000000084070c840@21ed7ce
那么这里到底发生了什么?
当你将一个参数绑定到一个值时,你已经明确地表达了类型(也许它是推断出来的,但它绝对是那个类型,在这种情况下是Int
s)。它是糖,所以我们不需要写它。但在底层,这些是组合函数,它们的组合方式非常重要。为了能够匹配和简化函数签名,编译器要求我们以由外向内的方式提供此信息。否则,我们需要给它一些帮助才能到达那里。
编辑:
我认为这个问题更像是 Scala 语言规范。然而,益智练习。从设计的角度来看,我想不出任何好的理由,为此您需要以这样一种方式实现一个柯里化函数,即您不能对参数进行排序,以便最后一个参数是被推断的参数。
推荐阅读
- python - 收到我的 dict 对象在 Django 应用程序中没有属性 META 的错误
- php - 模型 [App\UserModel] 0 [ Laravel ] 没有查询结果
- android - SQLite SUM 得到值 0
- java - 如何在 jooq 查询中获取 springboot 事务的数据
- swift - 如何在不中断主线程的情况下快速延迟 for 循环?
- haskell - Haskell:用 if-else 语句理解 do 表示法
- javascript - 如何实现 JavaScript 时钟?
- amazon-web-services - 如何监控胶水爬虫执行统计信息?
- python - 如何迭代行并将值分配给新列
- javascript - MomentJS toISOString AM/PM 不正确