42

だから私はこのマクロを持っています:

import language.experimental.macros
import scala.reflect.macros.Context

class Foo
class Bar extends Foo { def launchMissiles = "launching" }

object FooExample {
  def foo: Foo = macro foo_impl
  def foo_impl(c: Context): c.Expr[Foo] =
    c.Expr[Foo](c.universe.reify(new Bar).tree)
}

fooを返したいと 3 回言いましたFooが、次のことができます (2.10.0-RC3 で):

scala> FooExample.foo
res0: Bar = Bar@4118f8dd

scala> res0.launchMissiles
res1: String = launching

いずれかの型パラメーターを削除すると、同じことが起こりますc.Exprfooを呼び出している人が を取得していることを確認できないようにしたい場合Barは、ツリー自体に型の割り当てを追加する必要があります。

これは実際には非常に優れています。たとえば、マクロをある種のスキーマに向けてVocabulary、ボキャブラリの用語を表すメンバー メソッドを使用して、クラスの匿名サブクラスを作成できます。これらは、返されたオブジェクトで使用できます。

自分が何をしているのかを正確に理解したいので、いくつか質問があります。まず、fooメソッドの戻り値の型は実際には何のためにあるのでしょうか? (オプションの)ドキュメントにのみ利用できますか?戻り値の型を明確に制限します (たとえば、この場合は変更できませんInt)。完全に削除すると、次のようなエラーが発生します。

scala> FooExample.foo
<console>:8: error: type mismatch;
 found   : Bar
 required: Nothing
              FooExample.foo
                         ^

しかし、私はそれをに変更することができ、呼び出し時にAny静的に型付けされたものを取得できます。Barfoo

第二に、この動作はどこかで指定されていますか? これはかなり基本的な一連の問題のように思えますが、明確な説明や議論を検索することはできませんでした。

4

1 に答える 1

22

紛らわしいように見えるかもしれませんが、この動作は指定されていませんが、意図されています。マクロ シグネチャでの戻り値の型の役割について詳しく説明する予定ですが、現時点では、柔軟性があることは良いことだと感じています。

Fooまた、動作が一貫していない場合もあります。たとえば、マクロが型推論の途中でキャッチされた場合、実際の展開の型ではなく、その静的シグネチャが使用されます (つまり、例では)。これは、型の推論が完了するまでマクロの展開が意図的に遅延されるためです (マクロの実装が型 var ではなく、推論された型を認識できるようにするため)。これはトレードオフであり、必ずしも最適なものではないため、すぐに再検討する予定です: https://issues.scala-lang.org/browse/SI-6755

この部門のもう 1 つの問題は、暗黙のマクロに関するものです。暗黙的なマクロの戻り値の型がジェネリックであり、暗黙的な値の要求された型から推測する必要がある場合、悪いことが起こります。これにより、マクロを使用して型タグを生成することが現在不可能になっています: https://issues.scala-lang.org/browse/SI-5923

于 2012-12-02T21:18:44.277 に答える