Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - Currying and default arguments

I have a function with two parameter lists that I am trying to partially apply and use with currying. The second parameter list contains arguments that all have default values (but not implicit). Something like this:

 def test(a: Int)(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }

Now, the following is all fine:

 test(1)(2, 3);
 test(1)(2);
 test(1)(c=3);
 test(1)();

Now if I define:

 def partial = test(1) _;

Then the following can be done:

 partial(2, 3);

Can someone explain why I can't omit some/all arguments in 'partial' as follows:

 partial(2);
 partial(c=3);
 partial();

Shouldn't writing "partial" behave essentially the same way as "test(1)"? Can someone please help me figure out a way to achieve this?

Please help, I'm desperate!

EDIT - Since I can't answer my own question within 24 hours, I'll post my own answer here:

This is the best I could do myself so far:

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();

This way it works...

like image 985
Learner Avatar asked Apr 15 '11 11:04

Learner


2 Answers

The type inference engine gives to partial the type of what comes next; i.e., the eta expansion test(1) _. You can see e.g. in the REPL that partial has type (Int, Int) => Unit, whereas test has type (a: Int)(b: Int,c: Int)Unit. The result of the eta expansion is a Function object, which does not carry any argument names with it (as it is possible to define Function with anonymous parameters).

To fix this, you have to define partial as follows:

def partial(b: Int = 2, c: Int = 3) = test(1)(b,c)

Maybe you'll want to factor out the default values where both test and partial can reach them to make sure they stay equal. But I know of no trick to avoid repeating the names of the parameters without introducing extra overhead like creating of new objects, etc.

like image 50
Jean-Philippe Pellet Avatar answered Sep 18 '22 08:09

Jean-Philippe Pellet


This is the best I could do myself so far:

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();

This way it works...

like image 30
Learner Avatar answered Sep 22 '22 08:09

Learner