Scala - аргументы Currying и default

У меня есть функция с двумя списками параметров, которые я пытаюсь частично применить и использовать с currying. Второй список параметров содержит аргументы, которые имеют значения по умолчанию (но не подразумеваемые). Что-то вроде этого:

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

Теперь все нормально:

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

Теперь, если я определяю:

 def partial = test(1) _;

Тогда можно сделать следующее:

 partial(2, 3);

Может кто-нибудь объяснить, почему я не могу опустить некоторые/все аргументы в "partial" следующим образом:

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

Не следует ли писать "частичные" по существу так же, как "test (1)"? Может кто-то, пожалуйста, помогите мне выяснить способ достижения этого?

Пожалуйста, помогите, я в отчаянии!

EDIT. Поскольку я не могу ответить на свой вопрос в течение 24 часов, я отправлю свой собственный ответ здесь:

Это лучшее, что я мог сделать до сих пор:

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();

Таким образом, он работает...

Ответ 1

Это лучшее, что я мог сделать до сих пор:

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();

Таким образом, он работает...

Ответ 2

Механизм вывода типа дает partial тип следующего; т.е. это расширение test(1) _. Вы можете видеть, например. в REPL, что partial имеет тип (Int, Int) => Unit, тогда как test имеет тип (a: Int)(b: Int,c: Int)Unit. Результатом расширения eta является объект Function, который не несет с ним никаких имен аргументов (так как можно определить Function с анонимными параметрами).

Чтобы исправить это, вы должны определить partial следующим образом:

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

Возможно, вам захочется отбросить значения по умолчанию, где оба test и partial могут достигнуть их, чтобы убедиться, что они остаются равными. Но я не знаю трюка, чтобы избежать повторения имен параметров без введения дополнительных накладных расходов, таких как создание новых объектов и т.д.

Ответ 3

Следуя вашему комментарию, здесь более компактный способ его записи:

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

Это немного более компактно, чем ваше предложение, но менее эффективно, поскольку любой вызов внутреннего apply будет происходить через отражение, как со структурными типами. На самом деле тип возврата test является структурным типом:

 java.lang.Object{def apply(b: Int,c: Int): Unit; def apply$default$1: 
 Int @scala.annotation.unchecked.uncheckedVariance; def apply$default$2: Int 
 @scala.annotation.unchecked.uncheckedVariance}