Вчера @Krzysztof Atłasik помог мне выяснить, как уменьшить избыточность в сопоставлении с помощью частичных функций, так что раньше выглядело так:
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.
теперь выглядит так:
object RomanNumerals {
def roman(i: Int)(implicit romanNumeral: String = ""): String =
this.tryRoman(romanNumeral)
.orElse(this.tryRoman(1000, "M", romanNumeral))
.orElse(this.tryRoman(900, "CM", romanNumeral))
.orElse(this.tryRoman(500, "D", romanNumeral))
.orElse(this.tryRoman(400, "CD", romanNumeral))
.orElse(this.tryRoman(100, "C", romanNumeral))
.orElse(this.tryRoman(90, "XC", romanNumeral))
.orElse(this.tryRoman(50, "L", romanNumeral))
.orElse(this.tryRoman(40, "XL", romanNumeral))
.orElse(this.tryRoman(10, "X", romanNumeral))
.orElse(this.tryRoman(9, "IX", romanNumeral))
.orElse(this.tryRoman(5, "V", romanNumeral))
.orElse(this.tryRoman(4, "IV", romanNumeral))
.orElse(this.tryRoman(1, "I", romanNumeral))
.apply(i)
private def tryRoman(romanNumeral: String = ""): PartialFunction[Int, String] = {
case value if value == 0 => romanNumeral
}
private def tryRoman(
upperGuard: Int,
token: String,
romanNumeral: String
): PartialFunction[Int, String] = {
case value if value >= upperGuard =>
this.roman(value - upperGuard)(s"$romanNumeral$token")
}
}
Хорошо, это более кратко и значительно сухее, но я думаю, что хотел бы пойти еще дальше.
Я поместил все свои значения в ListMap, например:
val romanNumeralByValue: ListMap[Int, String] = ListMap(
1000 → "M",
900 → "CM",
500 → "D",
400 → "CD",
100 → "C",
90 → "XC",
50 → "L",
40 → "XL",
10 → "X",
9 → "IX",
5 → "V",
4 → "IV",
1 → "I"
)
Теперь я пытаюсь понять, как преобразовать эту карту в серию парциальных функций.
Я думал, что это будет что-то вроде:
def roman(i: Int)(implicit romanNumeral: String = ""): String = {
romanNumeralByValue.reduce(tryRoman){
case (keyvalue, accumulator) ⇒
accumulator
.orElse(this.tryRoman(keyvalue._1, keyvalue._2, romanNumeral))
}.apply(i)
}
Но этоне компилируется.
Есть идеи, как сделать эту работу?
Спасибо!