[英]how to define a type alias for a higher kinded type by a scala macro annotation (preferably using quasiquotes)
我开发了一个Scala宏批注,该批注丰富了具有各种定义的对象(请参见play form macro )。 除其他外,我希望对象包含类型别名
type WFS = FS[_, _, _, _]
用于不同数量的通配符参数。
我已经尝试通过提取单个通配符类型的值
q"type WFS = FS[_]" match { q"type WFS = FS[$t]" => t }
并希望在类型参数列表中使用提取的值(例如q“ type WFS = FS [.. $ tplist]”)。 但是上面的语句产生了一个错误:
scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$t]" => t }
scala.MatchError: type WFS = FS[_$1] forSome {
<synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any
} (of class scala.reflect.internal.Trees$TypeDef)
at .<init>(<console>:15)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43
还有另一种(也许更简单的)构造必要树的方法吗?
错误是打印要匹配的值的实际形状,显然您需要在匹配的准引用中使用相同的形状:
scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$a] forSome { $b }" => println(s"$a --- $b") }
_$1 --- <synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any
如果要允许更多的参数,而不仅仅是一个参数,则最好使用"..$x"
来实现:
scala> q"type WFS = FS[_]" match { case q"type WFS = FS[..$a] forSome { ..$b }" => println(s"$a --- $b") }
List(_$1) --- List(<synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any)
通配符转换为存在项— FS[_]
表示FS[T] forSome { type T }
(有关存在项的详细信息,请参见Scala语言规范,第3.2.10节,“存在类型的占位符语法”下)。 当你写FS[$a]
在您的匹配quasiquote,这意味着“我希望在这里类型构造的一个类型参数的应用程序”。 但是FS[T] forSome { type T }
是一种存在类型,其中包含对参数使用类型构造函数的应用程序,因此模式将不匹配。
为了更好地理解并且知道如何调试类似的问题,使用showRaw
查看由showRaw
生成的树是很有见地的-因为这些是类型,所以我们需要准引用类型,即tq"..."
:
scala> showRaw(tq"FS[_]")
res15: String = ExistentialTypeTree(AppliedTypeTree(Ident(newTypeName("FS")), List(Ident(newTypeName("_$1")))), List(TypeDef(Modifiers(DEFERRED | SYNTHETIC), newTypeName("_$1"), List(), TypeBoundsTree(Select(Select(Ident(nme.ROOTPKG), newTermName("scala")), newTypeName("Nothing")), Select(Select(Ident(nme.ROOTPKG), newTermName("scala")), newTypeName("Any"))))))
scala> showRaw(tq"FS[T]")
res16: String = AppliedTypeTree(Ident(newTypeName("FS")), List(Ident(newTypeName("T"))))
据我了解,与准引用匹配意味着与相应的树匹配。 因此以上说明了我描述的问题。
不幸的是,准引号没有隐藏Scala类型系统的此类细节。 那可能是也可能不是准引用的错误,但是我无法对此发表评论-我确实认为,如果不需要处理,那将很酷
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.