2

I'm fairly new to Scala and functional programming in general so I'm having a bit trouble wrapping my head around the concept of partially applied functions and function currying. There's also a pretty high chance that I'm gonna mix up some terminology, so all corrections are appreciated.

Note: I'm using the Scala Play framework but this is more of a Scala problem than a Play problem.

Given a function like this

def create(id: Long, userId: Long, label: String)

I get the userId and label as a (Int, String) tuple and the id as a Long. Basically what I'm trying to do is passing the id and the tuple to the function at the same time.

Now, I've read that passing a tuple to a function can be done something like this

scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int

scala> (f _).tupled((2, "Hello"))
res0: Int = 0

and that it is also possible to partially apply a function like this

scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int

scala> val ff = f(_: Int, "Hello")
ff: Int => Int = <function1>

scala> ff(2)
res1: Int = 0

So my initial idea was to combine these two concepts something like this

scala> def g(a: Long, b: Int, c: String) = 0
g: (a: Long, b: Int, c: String)Int

scala> val h = g(1, _: Int, _: String)
h: (Int, String) => Int = <function2>

scala> (h _).tupled((2, "Hello"))

However this results in an error

<console>:10: error: _ must follow method; cannot follow h.type
              (h _).tupled((1, "Hello"))
               ^

So my question is first of all why doesn't this work because to me this makes sense. And secondly how would I go about achieving this effect?

Thanks for your help!

Kai Sassnowski
  • 270
  • 2
  • 8

1 Answers1

3

Just don't abstract it twice: don't do redundand underscore to the h as it's already a function after partial-applying:

scala> def create(a: Long, b: Int, c: String) = 0
create: (a: Long, b: Int, c: String)Int

scala> val h = create(1, _: Int, _: String)
h: (Int, String) => Int = <function2>

scala> h.tupled((1, "Hello"))
res0: Int = 0

More deeply, tupled is defined on functions (means object of Function, like Int => String), not on methods (like def f(i: Int): String) - so sometimes you need to convert a method to the function - it's called eta-expansion (or eta-abstraction more generally). When you do partial applying - eta-expansion is done automatically (you already have a (Int, String) => Int) - so you don't have to do it twice.

See The differences between underscore usage in these scala's methods, Difference between method and function in Scala for more information.

Community
  • 1
  • 1
dk14
  • 22,206
  • 4
  • 51
  • 88