2

オブジェクトをさまざまな定義で強化する scala マクロ アノテーションを開発しています ( cf. play form マクロ)。とりわけ、オブジェクトにタイプエイリアスが含まれていることを望みます

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

必要なツリーを構築するための別の (おそらくもっと簡単な) 方法はありますか?

4

1 に答える 1

0

エラーは、一致している値の実際の形状を出力しています。明らかに、一致する準引用符で同じ形状を使用する必要があります。

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

1つだけでなく、より多くのパラメーターを許可したい場合は、それを許可するために使用することをお勧めします"..$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]と、それは「ここでは、型コンストラクターを1つの型引数に適用することを期待しています」という意味です。ただし、型コンストラクターの引数への適用を含むFS[T] forSome { type T }存在型であるため、パターンは一致しません。

それをよりよく理解し、同様の問題をデバッグする方法を知るために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 型システムのそのような詳細を隠していないのは残念です。それは quasiquotes のバグかもしれませんし、そうでないかもしれませんが、それについてコメントすることはできません。

于 2014-02-04T21:37:48.430 に答える