Можно ли разложить операторы соответствия Scala с помощью частичных функций?

У меня есть такое заявление о совпадении:

    i match {
      case x if x == 0 ⇒
        romanNumeral

      case x if x >= 1000 ⇒
        this.roman(i - 1000, s"${romanNumeral}M")

      case x if x >= 900 ⇒
        this.roman(i - 900, s"${romanNumeral}CM")

      // etc.

В зависимости от того, как это отформатировано, это может быть около 30 строк избыточного кода. Поэтому мне интересно, можно ли сделать этот код более сухим.

Итак, я создал частичную функцию:

  private def toRoman(upperGuard: Int, token: String, romanNumeral: String): String = {
    case value: Int if value >= upperGuard ⇒
      this.roman(upperGuard - 1, s"$romanNumeral$token")
  }

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

    i match {
      case x if x == 0 ⇒
        romanNumeral

        toRoman(1000, "M", romanNumeral)
        toRoman(900, "CM", romanNumeral)
        // etc.

... Но это не сработает, потому что компилятор Scala не распознает эти функции как операторы case, которые он ищет.

Есть ли способ заставить это работать?


person Brian Kessler    schedule 27.10.2019    source источник
comment
Пожалуйста, не оставляйте повторяющиеся комментарии, так как они бесполезны. Если вы публикуете то, что может быть воспринято как код низкого качества, что вы и сделали, вы можете ожидать ответов, которые прокомментируют это. Вам было бы лучше прочитать ответы более внимательно, прежде чем быстро минусовать и копировать и вставлять комментарии. Удачного кодирования.   -  person Derrops    schedule 28.10.2019
comment
@ Snickers3192, я прочитал твой ответ. Это не дало мне никакой полезной информации, кроме как не согласиться с предпосылкой вопроса, который явно бесполезен. Сравните с ответом Кшиштофа, где он увидел, что я намеревался сделать, и сказал мне, как это сделать.   -  person Brian Kessler    schedule 28.10.2019


Ответы (3)


Вы можете создавать свои случаи как частичные функции:

private def toRoman(upperGuard: Int, token: String, romanNumeral: String): PartialFunction[Int, String] = {
    case value if value >= upperGuard =>
      this.roman(upperGuard - 1, s"$romanNumeral$token")
}

val firstCase: PartialFunction[Int, String] = {
    case x if x == 0 => romanNumeral
}

А затем составить его следующим образом:

val toRomanPartialFunction = firstCase
  .orElse(toRoman(1000, "M", romanNumeral))
  .orElse(toRoman(900, "CM", romanNumeral))

После этого вы можете использовать его как обычную функцию:

toRomanPartialFunction.apply(443) 
toRomanPartialFunction(443) 
person Krzysztof Atłasik    schedule 28.10.2019
comment
Это звучит как именно то, что я ищу! Но почему применяется последняя строка (443)? Мне это нужно? Что вообще означает содержащееся значение? Или конкретно здесь? - person Brian Kessler; 28.10.2019
comment
@BrianKessler PartialFunction работает как обычная функция, поэтому вы можете вызывать с помощью apply() или просто (). Я обновил свой ответ, может быть, на этот раз он более понятен. - person Krzysztof Atłasik; 28.10.2019

Таким образом, вы в основном хотите сделать код менее повторяющимся, обо всем по порядку:

  • Компилятор Scala не распознает эти функции как операторы case, потому что они являются функциями;
  • Во-вторых, эта функция на самом деле не является частичной функцией;
  • Наконец, эти совпадения могут быть такими, если вы найдете способ сократить строки кода, сгруппировав какую-то функцию, как вы отлично сделали, но я не нахожу их излишними, если только вы не можете повторить это с помощью такой функции, как Я сказал.

Ps: эта функция не делает что-то, как в случае

person Pedro Correia Luís    schedule 27.10.2019
comment
Пожалуйста, смотрите ответ @Krzysztof Atłasik. Я еще не принял (подлежит тестированию), но он, кажется, понял, что я пытаюсь сделать, и сосредоточился на намерении, а не на реализации (мне было все равно на слово «совпадение»). - person Brian Kessler; 28.10.2019

У вас нет выражения для сопоставления с образцом, вы просто пишете оператор if else. Если вы хотите вернуть функцию, вы должны написать: x => this.something(x,"foo-bar") Вам не нужно case x. Если у вас есть только одно выражение в LHS case x, вам не нужно сопоставление с образцом, и вы можете просто использовать if else. Сопоставление с образцом без иерархии классов не имеет смысла.

person Derrops    schedule 28.10.2019
comment
Пожалуйста, смотрите ответ @Krzysztof Atłasik. Я еще не принял (подлежит тестированию), но он, кажется, понял, что я пытаюсь сделать, и сосредоточился на намерении, а не на реализации (мне было все равно на слово «совпадение»). - person Brian Kessler; 28.10.2019
comment
Пожалуйста, смотрите мой ответ. - person Derrops; 28.10.2019