Using partial functions in Scala - how does it work?

前端 未结 2 1387
梦谈多话
梦谈多话 2020-12-02 03:48

I\'m new to Scala, I\'m using 2.9.1, and I\'m trying to get my head around how to use partial functions. I have a basic understanding of curried functions, and I know that

2条回答
  •  孤城傲影
    2020-12-02 04:32

    A partial function is a function that is valid for only a subset of values of those types you might pass in 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 when you have something that knows how to check whether a function is defined or not. Collect, for instance:

    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 is not going to help you place two arguments where you really want one.

    In contrast, a partially applied function is a function where some of its arguments have already been filled in.

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

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

    scala> add5(2)
    res3: Int = 7
    

    You can see from this example how to use it.

    But if you need to specify those two arguments, this still won't do it--say you want to use map, for instance, and you need to give it a function of one argument, but you want it to add two different things. Well, then you can

    val addTupled = (add _).tupled
    

    which will partially apply the function (really, just create a function out of the method, since nothing has been filled in) and then combine the separate arguments into a tuple. Now you can use this in places that require a single argument (assuming that the type is correct):

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

    In contrast, currying is different yet again; it turns functions of the form (A,B) => C into A => B => C. That is, given a function of multiple arguments, it will produce a chain of functions that each take one argument and return a chain one shorter (you can think of it as partially applying one argument at a time).

    val addCurried = (add _).curried
    
    scala> List(1,4,3).map(addCurried)
    res5: List[Int => Int] = List(, , )
    
    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
    

提交回复
热议问题