В Scala, возможно ли иметь «частично ленивое» вычисление динамически вычисляемой частичной функции? - PullRequest
1 голос
/ 31 октября 2019

С помощью @Luis Miguel Mejía Suárez у меня есть динамически рассчитанная частичная функция для преобразования арабских чисел в римские цифры:

import scala.collection.immutable.ListMap
import scala.collection.mutable.StringBuilder  

object RomanNumerals {
  private 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"
  )

  private val tryRomanStep: (Int, String) => PartialFunction[Int, (Int, String)] =
    (upperLimit, result) => {
      case value if (value >= upperLimit) =>
        upperLimit -> result
    }

  private val tryRoman: PartialFunction[Int, (Int, String)] =
    romanNumeralByValue.map(tryRomanStep.tupled).reduce {
      (acc, f) => acc.orElse(f)
    }

  def roman(i: Int): String = {
    @annotation.tailrec
    def loop(remainingValue: Int, acc: StringBuilder): String =
      if (remainingValue == 0)
        acc.result()
      else {
        val (removedValue, newToken) = tryRoman(remainingValue)
        loop(remainingValue - removedValue, acc.append(newToken))
      }

    loop(
      remainingValue = i,
      acc = new StringBuilder()
    )
  }
}

Согласно Луису, «цепочка функций строится и сокращается простоодин раз. "

Очевидно, что это уже сверхмощная игрушка с гораздо большей сложностью, чем требует проблема, но я мог (смутно) представить некоторый немного похожий сценарий, в котором вычисление частичной функции менее тривиально.

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

Например,если первый вызов обеспечивает ввод «1000», второй вызов функции уже «знает», что это разрешается как «M», но затем он все равно может продолжить вычислять (например), что «100» возвращает «C». «В этот момент третий вызов будет знать только так много, новсе еще можно было бы разрешить больше ... и вся частичная функция не будет "известна", пока не будет предоставлено значение меньше 4?

...