【问题标题】:Simple tax calculation in ScalaScala中的简单税收计算
【发布时间】:2023-03-13 23:35:01
【问题描述】:

假设我正在编写一个具有两个功能的玩具税计算器:

// calculate the tax amount for a particular income given tax brackets
def tax(income: BigDecimal, brackets: Seq[Bracket]): BigDecimal = ???

// calculate the min. income for a particular tax rate given tax brackets 
def income(taxRate: BigDecimal, brackets: Seq[Bracket]) = ???

我这样定义一个税级:

case class Bracket(maxIncomeOpt: Option[BigDecimal], rate: BigDecimal)

Bracket(Some(BigDecimal(10)), BigDecimal(10)) 表示10% 的税级,用于收入超过10 Bracket(Some(BigDecimal(20)), BigDecimal(20)) 表示20% 的税级高于20
Bracket(None, BigDecimal(30)) 表示30% 的税级用于任何收入

现在我正在编写函数tax,如下所示:

def tax(income: BigDecimal, brackets: Seq[Bracket]): BigDecimal = {
  val (_, result) = brackets.foldLeft((BigDecimal(0), income)) { case ((result, rest), curr) =>
    val taxable = curr.maxIncomeOpt.fold(rest)(_.min(rest))
    (result + taxable * curr.rate / 100.0, rest - taxable)
  }
  result
} 

函数tax 似乎有效,但认为Seq[Bracket] 不是定义税级的最佳方式。税级是不相交的“背靠背”区间的排序序列,末尾有一个开区间。您如何定义税级?

【问题讨论】:

    标签: scala numeric tax


    【解决方案1】:

    考虑使用代数数据类型定义括号并使用PositiveInfinity 模拟开区间的解决方案

    abstract class TaxBracket(val from: Double, val to: Double, val rate: Double) {
      def tax(income: Double) = {
        if (income >= from)
          if (to.isPosInfinity) (income - from) * rate
          else if (income - to > 0) (to - from) * rate
          else (income - (from - 1)) * rate
        else
          0.0
      }
    }
    case object A extends TaxBracket(0, 12500, 0.0)
    case object B extends TaxBracket(12501, 50000, 0.2)
    case object C extends TaxBracket(50001, 150000, 0.4)
    case object D extends TaxBracket(150001, Double.PositiveInfinity, 0.45)
    

    现在税收计算简化为

    def tax(income: Double, bands: List[TaxBracket]): Double =
      bands.map(_.tax(income)).sum
    

    例如,使用上面定义的UK tax bands,我们得到

    tax(60000, List(A, B, C, D)) // res0: Double = 11499.8
    

    可以验证here

    要获得给定有效税率的最低收入,请尝试

    def income(etr: Double, bands: List[TaxBracket]): Option[Double] = {
      bands.map(b => (b.from, b.to)).find { case (from, to) =>
        if (to.isPosInfinity) true
        else (tax(to, bands) / to) >= etr
      }.map { case (lowerBound, upperBound) => lowerBound }
    }
    
    income(0.4, List(A, B, C, D)) // res1: Option[Double] = Some(150001.0)
    

    【讨论】:

    • 不错!谢谢你。这个解决方案看起来非常简单。你将如何实现income 函数来计算最小值。给定有效税率的收入?
    【解决方案2】:

    我建议大致相同,List[Tuple[Double, Double]] 作为原始形式。

    元组在语义上是(lower_bound, tax_rate_in_range)。关键区别在于行为的基本单位是税收表,而不是单个括号。在此核心数据定义的计划内,如果数字括号变大,您可以添加优化,并且您可以为简单的解决方案保留重要的不变量,例如保持由lower_bound 排序的列表。

    【讨论】:

      【解决方案3】:

      我会将税级定义为分段常数函数:

      def taxBracket(i: Int): Float = {
        case _ if i < 10 => 0.1
        case _ if i < 20 => 0.2
        case _ => 0.3
      }
      

      它易于阅读,易于对任何类型的值进行自定义行为(假设它在某处或任何地方变为线性,实际上,您可以根据需要将各个部分捆绑在一起),并且计算金额 N 的税很简单该函数在 0 和 N 之间的数值积分。

      【讨论】:

      • 谢谢。也许你是对的,这样的函数是模拟税级的更好方法。在这种情况下,您将如何编写 taxincome 函数?
      猜你喜欢
      • 2013-04-02
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多