Using partial functions in Scala - how does it work?

I am new to Scala, I am using 2.9.1 and I am trying to figure out how to use partial functions. I have a basic understanding of functions in curry, and I know that partial functions are similar to cardian functions, where they are only 2nary or some of them. As you can tell, I'm a little green.

It seems that in some cases, such as XML filtering, the possibility of partial functions will be very beneficial, so I hope to get a better idea of โ€‹โ€‹how to use them.

I have a function that uses the RewriteRule structure, but I need it to work with two arguments, while the RewriteRule structure accepts only one, OR partial function. I think this is one of those times when I think that it is useful.

Any advice, links, words of wisdom, etc. welcome!

The answers are still excellent and have clarified some of the fundamental misconceptions that I have. I think that they also explain what I'm struggling with - I think that perhaps a new question will be asked, which will be more specific, so I will do it too.

+47
scala functional-programming jvm-languages
Dec 28 2018-11-12T00:
source share
2 answers

A partial function is a function that is valid only for a subset of the values โ€‹โ€‹of those types that you could pass to it. For example:

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 

This is useful if you have something that knows how to check if a function is defined. Collect for example:

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

This does not help you place two arguments where you really want it.

In contrast, a partially applied function is a function in which some of its arguments are already filled.

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

Now you only need one argument - the thing is to add 5 in - instead of two:

 scala> add5(2) res3: Int = 7 

In this example, you can see how to use it.

But if you need to specify these two arguments, it wonโ€™t happen anyway - let's say you want to use map , for example, and you need to give it the function of one argument, but you want to add two different things to it. Well then you can

 val addTupled = (add _).tupled 

which will partially apply the function (in fact, just create a function from the method since nothing was filled), and then combine the individual arguments into a tuple. Now you can use this in places where one argument is required (assuming the type is correct):

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

In contrast, currying again; it turns functions of the form (A,B) => C into A => B => C That is, if a function of several arguments is specified, it will create a chain of functions, each of which will take one argument and return the chain even shorter (you can think of it as partial application of one argument at a time).

 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 
+133
Dec 28 2018-11-12T00:
source share

Rex Kerr's justification is very good - and not surprising. The question is to explicitly mix partial functions with partially applied functions. Whatever the cost, I was embarrassed when I recognized Scala.

However, since the question draws attention to partial functions, I would like to talk a little about them.

Many people say that partial functions are functions that are not defined for all input, and this is true for mathematics, but not for Scala. In Scala, a function cannot be defined for all input. In fact, since a partial function is inherited from the function, then the function includes all partial functions, making this inevitable.

Others mention the isDefinedAt method, which is really a difference, but mostly related to implementation. That Scala 2.10 is likely to be released with a "quick partial function" that does not rely on isDefinedAt .

And some people even imply that the apply method for partial functions does something different than the apply method for functions, for example, only executing for input - which cannot be further from the truth. The apply method is exactly the same.

What partial functions really come to naught is another method: orElse . This summarizes all the use cases for partial functions much better than isDefinedAt , because partial functions really do one of the following:

  • Chain partial functions (which orElse does), so the input will be checked for every partial function until one of them is there.
  • Doing something else if the partial function doesn't match, instead of throwing an exception, which will happen if you bind this other thing using orElse .

I'm not saying that everything can be easily implemented in terms of orElse , mind you. I'm just saying partial functions are doing something else when no input is defined for it.

+35
Dec 28 2018-11-12T00:
source share



All Articles