为什么我不能只对 Scala 中的第一个参数应用下划线?



我不知道为什么模式d在下面的列表中不好。为什么需要expicit类型声明?

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需要参数类型的原因。非常欢迎只显示引文语言规范

所以我相信这来自于部分应用程序的概念。

直观地,部分函数应用程序说"如果你修复了函数的第一个参数,你就得到了一个剩余参数的函数";

。。。

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

啊哈!

在英语中:";取CCD_ 4并返回取Int并返回CCD_;

如何使用此签名绑定第二个参数?除非我们首先经历了外部功能,否则我们如何才能进入内部功能?

据我所知,除非您明确定义了第一个参数的类型,否则使用这个签名是不可能的。

(但是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

那么这里到底发生了什么?

当您将一个参数绑定到一个值时,您已经显式地表达了类型(也许是推断的,但它肯定是那个类型,在本例中是Ints(。这是糖,所以我们不需要写它。但在引擎盖下,这些都是组合函数,它们是如何组合的非常重要。为了能够匹配和简化函数签名,编译器要求我们以内外入的方式提供这些信息。否则,我们需要给它一些帮助。

编辑:

然而,我认为这个问题更多的是一个Scala语言规范的谜题练习。从设计的角度来看,我想不出有什么好的理由需要以这样一种方式来实现一个curried函数,即不能对参数进行排序,从而使最后的参数是被推断的参数。

相关内容

最新更新