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

Scala3实现fuseMap融合宏时无法匹配连续map调用的问题

问题成因

宏始终走默认分支、无法完成map融合由两个核心错误导致:

  • simplify是inline方法,但参数x未加inline修饰。这种情况下宏接收到的Expr只是对simplify方法参数的引用,不是调用点传入的List(1,2,3).map(f).map(g)原始AST,表达式里根本不存在连续两次map的结构,不可能匹配成功。
  • 引号模式匹配中的类型变量误用反引号。Scala3宏的quote模式规则里,反引号包裹的类型代表「匹配当前作用域已存在的同名类型」,但代码中u、v是模式块内新声明的绑定类型变量,加反引号会让编译器去外部作用域查找不存在的u、v类型,直接导致匹配失败。

另外匹配分支开头有一行无赋值、无返回的孤立表达式'{ $ls.map(y => $g($f(y))) },属于冗余代码,不影响逻辑但可删除。

修正方法
  1. 给simplify方法的参数x加上inline修饰,保证宏能拿到调用点的原始表达式AST。
  2. 去掉模式匹配中u、v类型外层的反引号,让编译器正确将其识别为模式绑定的类型变量。

修正后的完整宏代码:

import scala.quoted.*

object macros:
  def fuseMap[T: Type](x: Expr[List[T]])(using Quotes): Expr[List[T]] =
    println("Initial passed in x: " + x.show)
    x match {
      case '{
            type u
            type v
            ($ls: List[u])
              .map($f: u => v)
              .map($g: v => T)
          } =>
        val result = '{ $ls.map(y => $g($f(y))) }
        println(result.show)
        result
      case _ =>
        println("fuseMap didn't do anything")
        x
    }

  inline def simplify[T](inline x: List[T]): List[T] = ${ fuseMap('x) }

原有调用侧代码不需要做任何修改,重新编译时就会命中map融合分支,打印出化简后的代码,运行后得到预期结果List(4, 6, 8)。

如果需要支持3次及以上的连续map融合,可以在构造完单次融合的表达式后递归调用fuseMap,处理完所有连续map链再返回即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 05:57:38