15

Looking at Programming in Scala (control abstraction) I saw these two examples that have the same effect:

1. Higher-Order Function

def withPrintWriter(file: File, op: PrintWriter => Unit) {
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
    writer.close()
  }
}

2. Currying function

def withPrintWriter(file: File)(op: PrintWriter => Unit) {
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
    writer.close()
  }
}

What is the difference between them? Can we always achieve the same result in both ways?

ROLO
  • 4,183
  • 25
  • 41
igx
  • 4,101
  • 11
  • 43
  • 88
  • 1
    Please look at this question: http://stackoverflow.com/questions/8063325/usefulness-as-in-practical-applications-of-currying-v-s-partial-application-i – red1ynx Sep 16 '13 at 13:20

5 Answers5

29

The concepts of higher-order functions and curried functions are generally used in an orthogonal way. A higher-order function is simply a function that takes a function as an argument or returns a function as a result, and it may or may not be curried. In general usage, someone referring to a higher-order function is usually talking about a function that takes another function as an argument.

A curried function, on the other hand, is one that returns a function as its result. A fully curried function is a one-argument function that either returns an ordinary result or returns a fully curried function. Note that a curried function is necessarily a higher-order function, since it returns a function as its result.

Thus, your second example is an example of a curried function that returns a higher-order function. Here's another example of curried function that does not take a function as an argument, expressed in various (nearly equivalent) ways:

def plus(a: Int)(b:Int) = a + b
def plus(a: Int) = (b: Int) => a + b
val plus = (a: Int) => (b: Int) => a + b
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
7

Higher order functions are functions that either take functions as parameter or return functions or both.

def f(g: Int => Int) = g(_: Int) + 23

scala> f(_ + 45)
res1: Int => Int = <function1>

scala> res1(4)
res2: Int = 72

This is a higher order function, it takes a function as parameter and returns another function. As you can see, higher order functions are a pre-requisite for currying. The curry function looks like this:

def curry[A,B,C](f: (A,B) => C) = (a: A) => (b: B) => f(a,b)

scala> curry((a: Int, b: Int) => a+b)
res3: Int => (Int => Int) = <function1>

scala> res3(3)
res4: Int => Int = <function1>

scala> res4(3)
res5: Int = 6

So to answer your question: They are two different concepts, where the one (higher order functions) is the pre-requisit for the other (currying).

drexin
  • 24,225
  • 4
  • 67
  • 81
3

Semantically, there is one difference I can think of between a curried and a not curried function. With the non-curried version, when you call withPrintWriter, that's a single method call. With the curried version, it's actually going to be two method calls. Think of it like this:

withPrintWriter.apply(file).apply(op)

Other than that, I think a lot of people use currying in this kind of situation for style. Using currying here makes this look more like a language feature then just a custom function call because you can use it like this:

withPrintWriter(file){ op =>
   ...
}

Using it in that way is trying to emulate some sore of control structure from the language itself, but again, this is only really a style thing and it does come with the overhead of an additional method call.

You can use the non-curried version in almost the same way, but it's not as clean looking:

withPrintWriter(file, { op =>
   ...
})

EDIT @drexin makes a good point in his answer that it's worth mentioning here for me. When you think of the signature of the curried version of the method, it's really:

Function1[File, Function1[PrintWriter, Unit]]
cmbaxter
  • 35,283
  • 4
  • 86
  • 95
  • 4
    This is not entirely true. The curried method gets compiled to a usual method on bytecode level and only partial application leads to an actual function object being created. If you fully apply it, it will be a single method call. – drexin Sep 16 '13 at 14:04
  • @drexin, thanks for the info. I did not know that. So I guess for this example, it boils down to style, unless you plan on partially applying it and then fully applying it somewhere else later with the single remaining arg. – cmbaxter Sep 16 '13 at 14:07
  • In fact it is just a matter of style, as you can partially apply any method and also convert a method into a curried function. See my post here for more information: http://stackoverflow.com/questions/12660852/why-does-currying-in-scala-need-multiple-parameter-lists/12660884#12660884 – drexin Sep 16 '13 at 14:14
1

They are mostly the same, but there is a difference with regard to type inference. Scala is not able to infer types between arguments of a single method invocation, but it is able to infer types for multiple argument lists.

Consider:

def foo1[T](x : T, y : T => T) = y(x)
def foo2[T](x : T)(y : T => T) = y(x)

foo1(1, t => t + 1) //does not compile with 'missing parameter type'
foo2(1)(t => t + 1) //compiles

You can see some additional information in this answer : Multiple parameter closure argument type not inferred

Community
  • 1
  • 1
Or Peles
  • 475
  • 1
  • 3
  • 8
0

Strictly speaking, the example you gave is not really curried, it just has multiple argument lists. It just happens that multiple argument list Scala functions look a lot like curried functions in many situations. However, when you call a multiple argument list function but don't fill in one or more argument lists, it's really an example of partial application, not currying. Calling a multiple argument list with all its arguments is just one function call, not one per argument list.

There are two use cases where multiple argument list functions are helpful. The first is the case of implicit parameters, since all implicit parameters have to be in their own argument list separate from any explicit parameters. The second use case is functions that accept other functions as parameters, since if a parameter that is a function is in its own argument list, you can leave off the parentheses and just use braces, making the function call look like some sort of control structure.

Other than that, the difference is purely cosmetic.

reggert
  • 732
  • 3
  • 10