передача параметра по умолчанию в scala?

Пожалуйста, рассмотрите следующий пример

def foo(a: Int, b: Int = 100) = a + b
def bar(a: Int, b: Int = 100) = foo(a, b) * 2

Это работает, но обратите внимание, что я должен указать одно и то же значение по умолчанию для b в обеих функциях. Мое намерение на самом деле следующее

def bar(a: Int, b: Int) = foo(a, b) * 2
def bar(a: Int)    = foo(a) * 2

Но это становится громоздким, когда у вас есть больше необязательных аргументов и дополнительных функций в цепочке (например, baz, которая вызывает bar таким же образом). Есть ли более краткий способ выразить это в scala?


person user881423    schedule 09.08.2012    source источник
comment
Четко сформулируйте свой вопрос: что вы считаете здесь громоздким? Что именно вы ищете? Если вы ищете более лаконичный способ записи параметров по умолчанию, то его нет, да и как быть?   -  person Nikita Volkov    schedule 09.08.2012


Ответы (2)


я не думаю, что есть; если вы скомпонуете foo с функцией удвоения:

val bar = (foo _).curried((_: Int)) andThen ((_: Int) *2)
// (please, please let there be a simpler way to do this...)

вы теряете аргументы по умолчанию, потому что объекты функций не имеют их.

Если это того стоит в вашем случае использования, вы можете создать класс case, содержащий ваши аргументы, которые вы передаете вместо нескольких отдельных, например.

case class Args(a: Int, b: Int = 100, c: Int = 42, d: Int = 69)
def foo(args: Args) = { import args._; a + b + c + d }
def bar(args: Args) = foo(args) * 2
person Luigi Plinge    schedule 09.08.2012
comment
Совершенно потрясающая техника. Это должен делать сам компилятор каждый раз, когда он сталкивается с перегруженным методом: конвертировать его в связанный класс данных и функцию. Функции гораздо удобнее для манипуляций, чем методы. - person ayvango; 09.08.2012
comment
Да, я думаю, что решение класса case - лучшее, что вы можете сделать. Однако кажется, что это может быть полезной функцией, которую можно легко реализовать в компиляторе scala. Я имею в виду что-то вроде этого: def bar(a: Int, b: Int = _) = foo(a, b) * 2, scala может проверить, что b используется только в тех местах, где было определено значение по умолчанию. , поэтому он может интерпретировать это без двусмысленности. - person user881423; 09.08.2012

Я бы предложил использовать Option.

def bar(a: Int, b: Option[Int] = None) = b match {
  case Some(x) => foo(a,x) * 2
  case _ => foo(a) * 2
}

Это точно сделает то, что вы хотите. Другим способом было бы использование varargs.

def baz(a: Int)(b: Int*) = b.headOption match {
  case Some(x) => foo(a,x) * 2
  case _ => foo(a) * 2
}

Я бы предпочел первый способ, потому что очевидно, что параметр является необязательным. Второе решение заключалось в том, чтобы не разбираться с обёрткой в ​​Option, но по сигнатуре непонятно, что будет учитываться только первый элемент коллекции. baz(1)(2) == baz(1)(2,3,4,5) верно.

Изменить

Чтобы вызов с Option выглядел как желаемый вызов, вы можете использовать имплициты.

implicit def int2Some(i: Int) = Some(i)

Теперь вы можете вызвать функцию следующим образом:

bar(1,2)
bar(1,Some(2))
bar(1)
bar(1,None)

implicit вызывается автоматически везде, где это полезно. Но ваши пользователи могут запутаться, почему функцию можно вызывать с Int вместо Option[Int].

person tgr    schedule 09.08.2012
comment
Первое решение не позволяет вам вызывать bar(1). Вы должны были бы сказать bar(1, None). Кроме того, то, что раньше было bar(1, 2), теперь нужно записать как bar(1, Some(2)). Использование повторяющегося параметра ближе к желаемому синтаксису, но я думаю, что это не сработает, если у вас есть два или более необязательных параметра? И да, у него также есть проблема, о которой вы упомянули. - person user881423; 09.08.2012
comment
Вы можете решить первую проблему, установив ее по умолчанию None. Я добавил это. - person tgr; 10.08.2012
comment
Вторая проблема может быть решена с помощью имплицитов. Я тоже добавил это. - person tgr; 10.08.2012
comment
Да, с исправлениями ваше решение достигает точного синтаксиса, который я хотел иметь. Однако, на мой взгляд, слишком много кода для реализации этой, казалось бы, простой функции. Рассмотрим случай, когда у вас больше необязательных параметров, вы получите такое же количество операторов сопоставления, и их придется повторять в каждой функции, которая хочет передать значение по умолчанию. Это много шаблонов, имхо, именно этого Scala пытается избежать. Еще одна небольшая проблема заключается в том, что значение по умолчанию int2some кажется немного опасным. Но спасибо за эту работу. Моя жалоба в основном касается компилятора Scala. - person user881423; 14.08.2012