繁体   English   中英

如何通过scala宏注释(最好使用准引用)为更高种类的类型定义类型别名

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM