Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to curry the other way around in Scala?

Let's assume this function:

def autoClosing(f: {def close();})(t: =>Unit) = {
    t
    f.close()
}

and this snippet:

val a = autoClosing(new X)(_)
a {
 println("before close")
}

is it possible to curry the first part? Something like:

val a = autoClosing(_) { println("before close") }

so that I could send the objects on which close should be performed, and have the same block executed on them?

like image 756
Geo Avatar asked Dec 17 '09 11:12

Geo


2 Answers

Yes, the snippet you have given works, as long as you give the type of the placeholder character.

Therefore, the code you are looking for is:

val a = autoClosing(_: {def close();}) { println("before close") }

which compiles and works as expected :).

A couple of notes:

  • You can make your life easier if you define a type alias for an AnyRef type having a close method, something like type Closeable = AnyRef {def close()}, or an appropriate interface.
  • The code snippet autoClosing(_: Closeable){ ... } is actually equivalent to the following expanded anonymous function: c: Closeable => autoClosing(c){ ... }. The wildcard character is just shorthand for a partially applied function. You need to give the type of the _ as the type inferer unfortunately cannot infer the type in this case.

Hope it helps,

-- Flaviu Cipcigan

like image 51
Flaviu Cipcigan Avatar answered Oct 11 '22 14:10

Flaviu Cipcigan


Alternatively you can flip the parameters:

def flip[A1, A2, B](f: A1 => A2 => B): A2 => A1 => B = x1 => x2 => f(x2)(x1)

In your case:

val a = flip(autoClosing){ println("before close") }

Edit: I've added some braces to help the human parser:

def flip[A1, A2, B](f: (A1 => (A2 => B))): (A2 => (A1 => B)) = {
    x1 => (x2 => f(x2)(x1))
}

Flip converts a function (A1 => (A2 => B)) to (A2 => (A1 => B)).

scala> def x(x1 : Int)(x2 : Long) = 1.0 * x1 / x2
x: (Int)(Long)Double

scala> val f = flip(x)
f: (Long) => (Int) => Double = <function>

scala> val g = f(1)
g: (Int) => Double = <function>

scala> val h = g(2)
h: Double = 2.0

scala> x(1)(2)
res0: Double = 0.5
like image 38
Thomas Jung Avatar answered Oct 11 '22 13:10

Thomas Jung