Scala函数组合遇类型不匹配错误,求排查及解决方法
你碰到的这个类型不匹配问题,根源在于Scala里的compose方法只支持单参数函数的组合,而你的generate是个接受两个Int参数的函数,两者类型不兼容才导致了报错。
先拆解下你的代码和报错细节:
你的函数定义:
def generate(start: Int, end: Int): Seq[Int] = (start until end).toSeq def restrain(seq: Seq[Int]) = seq.dropWhile(_ < 20).takeWhile(_ < 60)
generate的类型是(Int, Int) => Seq[Int](双参数函数),restrain的类型是Seq[Int] => Seq[Int](单参数函数)。
当你尝试restrain _ compose generate时,compose期望右侧的函数是单参数函数(输入是单个值,输出能匹配restrain的输入类型Seq[Int]),但generate需要两个参数,所以编译器才会提示:
val com: (Int, Int) => Seq[Int] = (restrain _ compose generate)
^ test.sc:1: error: type mismatch; found : (Int, Int) => Seq[Int] required: ? => Seq[Int]
几种可行的解决方案
1. 手动定义组合函数(最直观)
直接把两个函数的调用逻辑显式写在一起,完全避开函数组合方法的限制:
val com: (Int, Int) => Seq[Int] = (start, end) => restrain(generate(start, end))
这种方式代码清晰易懂,不需要额外的函数转换,适合大多数日常场景。
2. 将generate改为柯里化函数
柯里化会把双参数函数拆成嵌套的单参数函数,这样就能用compose或andThen来组合了:
// 改写generate为柯里化版本 def generate(start: Int)(end: Int): Seq[Int] = (start until end).toSeq // 用compose组合,此时generate的类型是Int => (Int => Seq[Int]) val com: Int => Int => Seq[Int] = restrain _ compose generate // 调用示例:com(10)(70)
如果你的代码风格偏向函数式编程,柯里化是个不错的选择,它还支持部分应用(比如先固定start参数,得到一个只接受end的函数)。
3. 把双参数函数转为接受元组的函数
Scala的Function2类型提供了tupled方法,可以把(Int, Int) => Seq[Int]转换成((Int, Int)) => Seq[Int](接受元组的单参数函数),这样就能和compose兼容了:
// 转换generate为接受元组的函数 val generateTuple: ((Int, Int)) => Seq[Int] = generate.tupled // 组合函数 val com: ((Int, Int)) => Seq[Int] = restrain _ compose generateTuple // 调用示例:com((10, 70))
这种方式适合需要和元组数据交互的场景,但调用时需要传入元组,不如前两种直观。
内容的提问来源于stack exchange,提问作者spacifici

