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))) },属于冗余代码,不影响逻辑但可删除。
修正方法
- 给
simplify方法的参数x加上inline修饰,保证宏能拿到调用点的原始表达式AST。 - 去掉模式匹配中
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
相关产品推荐
相关产品推荐

