Ple*_*exQ 47 functional-programming scala jvm-languages
我是Scala的新手,我正在使用2.9.1,而我正试图了解如何使用部分功能.我对curried函数有一个基本的了解,我知道部分函数有点像curried函数,它们只有2nary或者其他类似函数.你可以告诉我,我有点绿.
看起来在某些情况下,比如XML过滤,能够部分功能是非常有利的,所以我希望能更好地理解如何使用它们.
我有一个使用RewriteRule结构的函数,但我需要它使用两个参数,而RewriteRule结构只需要一个,或一个部分函数.我认为这是我认为它有用的案例之一.
任何建议,链接,智慧的话等欢迎!
到目前为止,答案非常好,并且澄清了我的一些基本误解.我认为他们也解释了我在哪里挣扎 - 我想也许发布一个更具体的新问题会有所帮助,所以我也会这样做.
Rex*_*err 142
部分函数是仅对您可能传递给它的那些类型的值的子集有效的函数.例如:
val root: PartialFunction[Double,Double] = {
case d if (d >= 0) => math.sqrt(d)
}
scala> root.isDefinedAt(-1)
res0: Boolean = false
scala> root(3)
res1: Double = 1.7320508075688772
Run Code Online (Sandbox Code Playgroud)
当您拥有了解如何检查函数是否已定义的内容时,这非常有用.收集,例如:
scala> List(0.5, -0.2, 4).collect(root) // List of _only roots which are defined_
res2: List[Double] = List(0.7071067811865476, 2.0)
Run Code Online (Sandbox Code Playgroud)
这不会帮助你将两个参数放在你真正需要的地方.
相反,部分应用的函数是其中一些参数已被填充的函数.
def add(i: Int, j: Int) = i + j
val add5 = add(_: Int,5)
Run Code Online (Sandbox Code Playgroud)
现在你只需要一个参数 - 添加5的东西 - 而不是两个:
scala> add5(2)
res3: Int = 7
Run Code Online (Sandbox Code Playgroud)
您可以从此示例中看到如何使用它.
但是如果你需要指定这两个参数,这仍然不会这样做 - 例如,你想要使用它map,你需要给它一个参数的函数,但你希望它添加两个不同的东西.那么,你可以
val addTupled = (add _).tupled
Run Code Online (Sandbox Code Playgroud)
这将部分应用该函数(实际上,只是从方法中创建一个函数,因为没有填充),然后将单独的参数组合成一个元组.现在,您可以在需要单个参数的位置使用它(假设类型正确):
scala> List((1,2), (4,5), (3,8)).map(addTupled)
res4: List[Int] = List(3, 9, 11)
Run Code Online (Sandbox Code Playgroud)
相比之下,currying又是不同的; 它将表单的功能(A,B) => C转换为A => B => C.也就是说,给定多个参数的函数,它将产生一系列函数,每个函数接受一个参数并返回一个较短的链(您可以将其视为一次部分应用一个参数).
val addCurried = (add _).curried
scala> List(1,4,3).map(addCurried)
res5: List[Int => Int] = List(<function1>, <function1>, <function1>)
scala> res5.head(2) // is the first function, should add 1
res6: Int = 3
scala> res5.tail.head(5) // Second function should add 4
res7: Int = 9
scala> res5.last(8) // Third function should add 3
res8: Int = 11
Run Code Online (Sandbox Code Playgroud)
Dan*_*ral 35
Rex Kerr的解释非常好 - 也就是说也就不足为奇了.问题显然是将部分功能与部分应用功能混合在一起.无论如何,当我学习Scala时,我自己也犯了同样的困惑.
但是,由于这个问题确实引起了对部分功能的关注,我想稍微谈谈它们.
许多人说部分函数是没有为所有输入定义的函数,这对于数学是正确的,而不是Scala的.在Scala中,也可能没有为所有输入定义函数.实际上,由于部分函数继承自函数,因此函数也包括所有部分函数,使其不可避免.
其他人提到了这种方法isDefinedAt,这确实是一种差异,但主要是关于实施的方法.这是真的,Scala 2.10可能会发布一个"快速部分功能",它不依赖于它isDefinedAt.
有些人甚至暗示apply部分函数的apply方法与函数的方法有所不同,比如只执行已定义的输入 - 这不能远离事实.该apply方法是完全一样的.
真正的部分功能是另一种方法:orElse.这比使用部分函数的所有用例总结要好得多isDefinedAt,因为部分函数实际上是关于执行以下操作之一:
orElse),以便在每个部分函数上尝试输入,直到其中一个匹配.orElse.我不是说一切都可以轻松实现orElse,请注意.我只是说部分函数是关于在没有为它定义输入时做其他事情.