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}