Scala 3中如何为依赖/多态函数编写扩展?
为Scala 3多态函数编写通用扩展方法
问题场景
尝试为多态函数实现applyOption扩展方法,将函数调用结果包装为Option,但原代码编译失败。原实现代码如下:
object PolyFnExtension { type Base[O] = Function1[Any, Any] { def apply(x: Any): O } extension [O](base: Base[O]) { def applyOption(x: Any): Option[O] = Some(base.apply(x)) } val poly = { (x: Any) => x: x.type } val poly2: [T] => (Seq[T] => Option[T]) = [T] => (x: Seq[T]) => x.headOption @main def main(): Unit = { println(Show.showType(poly)) println(Show.showType(poly2)) val r1: Option[Int] = poly.applyOption(1) println(r1) val r2: Option[String] = poly.applyOption("abc") println(r2) } }
编译错误
编译时出现类型不匹配错误:
> Task :core:compileScala [Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/PolyFnExtension.scala:27:43: Found: Option[Any] Required: Option[Int] Explanation =========== Tree: com.tribbloids.spike.dotty.PolyFnExtension.applyOption[Any]( com.tribbloids.spike.dotty.PolyFnExtension.poly)(1) I tried to show that Option[Any] conforms to Option[Int] but none of the attempts shown below succeeded: ==> Option[Any] <: Option[Int] CachedAppliedType CachedAppliedType ==> Any <: Int CachedTypeRef CachedTypeRef = false The tests were made under the empty constraint [Error] /home/peng/git/dottyspike/core/src/main/scala/com/tribbloids/spike/dotty/PolyFnExtension.scala:30:46: Found: Option[Any] Required: Option[String] Explanation =========== Tree: com.tribbloids.spike.dotty.PolyFnExtension.applyOption[Any]( com.tribbloids.spike.dotty.PolyFnExtension.poly)("abc") I tried to show that Option[Any] conforms to Option[String] but none of the attempts shown below succeeded: ==> Option[Any] <: Option[String] CachedAppliedType CachedAppliedType ==> Any <: String CachedTypeRef CachedTypeRef = false The tests were made under the empty constraint two errors found
补充需求
需要该扩展方法适配所有返回类型依赖输入类型的多态函数,例如:
{ val poly = { (x: Any) => x: x.type } val r1: Option[Int] = poly.applyOption(1) } { val poly = { (x: Any) => Seq(x: x.type) } val r1: Option[Seq[Int]] = poly.applyOption(1) }
正确实现
问题根源在于原代码的Base[O]类型将函数返回类型固定为单一的O,无法表达多态函数的依赖类型特性(返回类型随输入类型变化)。正确的实现需要利用Scala 3的多态函数类型和依赖类型推导:
object PolyFnExtension { // 定义通用多态函数类型:输入类型X对应返回类型由函数自身决定 type PolyFn = [X] => (X => Any) // 扩展方法使用依赖类型,让返回类型与输入类型关联 extension (base: PolyFn) { def applyOption[X](x: X): Option[base[X]] = Some(base(x)) } // 用Scala 3标准多态函数语法定义目标函数 val poly = [X] => (x: X) => x: x.type val polySeq = [X] => (x: X) => Seq(x: x.type) val poly2: [T] => (Seq[T] => Option[T]) = [T] => (x: Seq[T]) => x.headOption @main def main(): Unit = { val r1: Option[Int] = poly.applyOption(1) println(r1) // 输出: Some(1) val r2: Option[String] = poly.applyOption("abc") println(r2) // 输出: Some(abc) val r3: Option[Seq[Int]] = polySeq.applyOption(1) println(r3) // 输出: Some(List(1)) val r4: Option[Option[Int]] = poly2.applyOption(Seq(1,2,3)) println(r4) // 输出: Some(Some(1)) } }
关键说明
- 多态函数类型定义:
type PolyFn = [X] => (X => Any)明确表示这是一个接受任意类型X输入、返回对应类型结果的多态函数,而非接受Any输入的单态函数。 - 依赖类型推导:扩展方法中
base[X]表示当输入为类型X时,多态函数base的返回类型,编译器可以据此自动推导Option[base[X]]的具体类型(如Option[Int]、Option[Seq[Int]])。 - 标准多态函数写法:将原
val poly = { (x: Any) => x: x.type }改为[X] => (x: X) => x: x.type,让编译器识别其多态特性,而非单态的Any => Any函数。
内容的提问来源于stack exchange,提问作者tribbloid
相关产品推荐
相关产品推荐

