Scala-каррирование и аргументы по умолчанию
У меня есть функция с двумя списками параметров, которые я пытаюсь частично применить и использовать с каррингом. Второй список параметров содержит аргументы, которые имеют значения по умолчанию (но не являются неявными). Что-то вроде этого:
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();
Не следует писать "частичные" ведут себя по существу так же, как и"тест(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();
Вот как это работает...
3 ответа:
Механизм вывода типа дает
partial
тип того, что происходит дальше; т. е. расширение etatest(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
могут достичь их, чтобы убедиться, что они остаются равными. Но я не знаю никакого трюка, чтобы избежать повторения имен параметров без введения дополнительных накладных расходов, таких как создание новых объектов и т. д.
Это лучшее, что я мог сделать сам до сих пор:
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();
Вот как это работает...
Следуя вашему комментарию, вот более компактный способ его написания:
Это немного более компактно, чем ваше предложение, но менее эффективно, так как любой вызов внутреннего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}