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

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))
  }
}

关键说明

  1. 多态函数类型定义:type PolyFn = [X] => (X => Any)明确表示这是一个接受任意类型X输入、返回对应类型结果的多态函数,而非接受Any输入的单态函数。
  2. 依赖类型推导:扩展方法中base[X]表示当输入为类型X时,多态函数base的返回类型,编译器可以据此自动推导Option[base[X]]的具体类型(如Option[Int]、Option[Seq[Int]])。
  3. 标准多态函数写法:将原val poly = { (x: Any) => x: x.type }改为[X] => (x: X) => x: x.type,让编译器识别其多态特性,而非单态的Any => Any函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:53:19