You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala中如何组合部分应用函数?语法实现求助

问题解决:Scala函数组合与部分应用

核心问题

你的代码里round函数的参数顺序导致无法直接用andThen组合——average返回Option[Double],而andThen要求后续函数的输入类型与前一个的输出类型匹配,但当前round(2)并没有生成一个接收Option[Double]的函数,因为第二个参数(number: Option[Double])是最后一个参数,部分应用后无法直接形成适配的函数类型。

三种简单解决方案

方案1:调整round的参数顺序

把Option[Double]放在第一个参数位,这样部分应用第二个参数时就能得到符合要求的函数:

def average(data: Seq[Option[Double]]): Option[Double] = {
  val numbers = data.flatten
  numbers match {
    case ns if ns.isEmpty => None
    case ns => Some(ns.sum / ns.length)
  }
}

def roundHalfUp(d: Double, rounding: Int): Double = {
  BigDecimal(d).setScale(rounding, BigDecimal.RoundingMode.HALF_UP).doubleValue
}

// 调整参数顺序:先接收Option[Double],再接收保留位数
def round(number: Option[Double], rounding: Int): Option[Double] = {
  number match {
    case None => None
    case Some(n) => Some(roundHalfUp(n, rounding))
  }
}

// 用占位符部分应用rounding参数,生成接收Option[Double]的函数
val f = average andThen (round(_, 2))

// 注意:average需要Seq[Option[Double]],调用时要包装成Some
f(List(Some(1.23), Some(2.242), Some(3.345))) // 返回Some(2.27)

方案2:将round改为柯里化函数(推荐)

柯里化后,部分应用第一个参数(保留位数)会直接返回一个接收Option[Double]的函数,完美适配andThen:

def average(data: Seq[Option[Double]]): Option[Double] = {
  val numbers = data.flatten
  numbers match {
    case ns if ns.isEmpty => None
    case ns => Some(ns.sum / ns.length)
  }
}

def roundHalfUp(d: Double, rounding: Int): Double = {
  BigDecimal(d).setScale(rounding, BigDecimal.RoundingMode.HALF_UP).doubleValue
}

// 柯里化:先传保留位数,再传要处理的Option[Double]
def round(rounding: Int)(number: Option[Double]): Option[Double] = {
  number match {
    case None => None
    case Some(n) => Some(roundHalfUp(n, rounding))
  }
}

// 直接组合,round(2)就是接收Option[Double]的函数
val f = average andThen round(2)

f(List(Some(1.23), Some(2.242), Some(3.345))) // 返回Some(2.27)

方案3:不修改原函数,用匿名函数包装

如果不想改动现有round函数的定义,用匿名函数把round(2, num)包装成接收Option[Double]的函数:

// 保留你原有的average、roundHalfUp、round函数不变
val f = average andThen (num => round(2, num))

f(List(Some(1.23), Some(2.242), Some(3.345))) // 返回Some(2.27)

额外提示

你原调用代码里的List(1.23, 2.242, 3.345)是List[Double],但average要求Seq[Option[Double]],所以需要把每个元素用Some包装,或者给average加个重载来处理Seq[Double]:

// 重载average,支持直接接收Double序列
def average(data: Seq[Double]): Option[Double] = average(data.map(Some(_)))
// 这样就可以直接调用f(List(1.23, 2.242, 3.345))

内容的提问来源于stack exchange,提问作者David Regan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 07:50:58