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
相关产品推荐
相关产品推荐

