在Scala中使用部分函数 – 它是如何工作的?

我是新来的Scala,我正在使用2.9.1,并且试图让我的头部如何使用部分函数。 我对咖喱函数有一个基本的了解,而且我知道,局部函数就像是二元或者其他类似的咖喱函数。 正如你可以告诉我有点在这个绿色。

似乎在某些情况下,如XML过滤,能够部分function将是非常有利的,所以我希望更好地了解如何使用它们。

我有一个使用RewriteRule结构的函数,但是我需要它使用两个参数,而RewriteRule结构只有一个,或者是一个部分函数。 我认为这是我正在考虑有帮助的情况之一。

任何build议,链接,智慧的话等欢迎!

迄今为止的答案是非常好的,已经澄清了我的一些基本误解。 我想他们也解释我在哪里挣扎 – 我想也许发布一个更具体的新问题将有所帮助,所以我也会这样做。

部分函数是一个函数,只对那些可能传递给它的types的值的子集有效。 例如:

 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 

当你有一些知道如何检查一个函数是否被定义的时候,这是很有用的。 收集,例如:

 scala> List(0.5, -0.2, 4).collect(root) // List of _only roots which are defined_ res2: List[Double] = List(0.7071067811865476, 2.0) 

不会帮助你在你真正想要的地方放置两个参数。

相反, 部分应用的函数是其中一些参数已被填充的函数。

 def add(i: Int, j: Int) = i + j val add5 = add(_: Int,5) 

现在你只需要一个参数 – 将5添加到 – 而不是两个:

 scala> add5(2) res3: Int = 7 

你可以从这个例子看到如何使用它。

但是,如果你需要指定这两个参数,这仍然不会 – 例如你想要使用map ,并且你需要给它一个参数的函数,但是你想要它添加两个不同的东西。 那么,你可以

 val addTupled = (add _).tupled 

这将部分地应用该函数(实际上,只是从方法中创build一个函数,因为没有填充),然后将单独的参数组合到一个元组中。 现在你可以在需要一个参数的地方使用它(假设types是正确的):

 scala> List((1,2), (4,5), (3,8)).map(addTupled) res4: List[Int] = List(3, 9, 11) 

相比之下, 咖喱又是不同的。 它将(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 

雷克斯·克尔的解释非常好 – 也不足为奇。 问题是将部分function部分应用的function混合在一起。 无论什么价值,我在学习Scala的时候自己也一样。

但是,由于这个问题确实引起了部分职能的关注,所以我想谈一谈。

很多人说部分函数是没有为所有input定义的函数,math是这样的,而不是斯卡拉。 在Scala中,函数也不一定为所有input定义。 实际上,由于部分函数inheritance了函数,所以函数也包含了所有的部分函数,​​这是不可避免的。

其他人提到方法isDefinedAt ,这实际上是一个区别,但主要是关于实现。 这是真的,斯卡拉2.10可能会被释放一个“快速部分函数”,它不依赖isDefinedAt

还有一些人甚至暗示,部分函数的apply方法和函数的apply方法有些不同,比如只执行被定义的input – 这不能离实际更远。 apply方法是完全一样的

真正归结为什么部分function是另一种方法: orElse 。 总结了部分函数的所有用例,比起isDefinedAt要好得多,因为部分函数实际上是要做下面的事情之一:

  • 链接部分函数(这是什么或orElse ),以便每个部分函数将尝试input,直到其中一个匹配。
  • 如果部分函数不匹配,则做一些不同的事情,而不是抛出exception,如果使用orElse链接不同的东西,会发生什么情况。

我并不是说所有事情都可以通过orElse 轻松实现,请介意。 我只是说,部分function是关于做一些别的东西,当input没有被定义。