1

DSL の場合、次のようなことができるようにしたいと考えています。

object Creator { 
   def create[T](s :String) :Foo[T] = macro createImpl[T]
   def createImpl[T](c :Context)(s :c.Expr[String]) : c.Expr[Foo[T]] = {
        reify(new Foo[Any]())
   }
 }

私の問題は、Anyin reify を、正しくパラメータ化されたバージョンを返すものに置き換えることです。

(上記では文字列引数を使用していますが、最終バージョンでは、クラス T のコンパニオン オブジェクトをマーカーとして使用して、Function1[T,Unit] の引数の型を知る予定です)

4

1 に答える 1

2

次のことを行う必要があります: a) (簡単な)new Foo[T]()の代わりに書き込みますnew Foo[Any]()b) マクロに type の表現T、つまり type の値を渡しAbsTypeTag[T]ます。T[T: c.AbsTypeTag]

Scala 2.10.0-M7 でテストしたコードを次に示します。編集します。2.10.0-RC1AbsTypeTagでは、名前が に変更されましたWeakTypeTag。マクロと型タグに関する他のすべては同じままです。

Creator.scala:

import language.experimental.macros
import reflect.macros.Context
class Foo[T]
object Creator {
  def create[T](s: String): Foo[T] = macro createImpl[T]
  def createImpl[T: c.AbsTypeTag](c: Context)(s: c.Expr[String]): c.Expr[Foo[T]] = {
    import c.universe._
    reify(new Foo[T]())
  }
}

MacroClient.scala:

object Main extends App {
  println (Creator.create[Int](""))
}

type パラメータを省略すると、奇妙なエラーが発生することに注意してください。

scala> Creator.create[Int]("")
res2: Foo[Int] = Foo@4888884e

scala> Creator.create("")
<console>:12: error: macro has not been expanded
              Creator.create("")
                      ^

また、次のようにも書きます。

(上記では文字列引数を使用していますが、最終バージョンでは、クラス T のコンパニオン オブジェクトをマーカーとして使用して、Function1[T,Unit] の引数の型を知る予定です)

しかし、私がそれを正しければ、これは悪い考えのように聞こえます。を書く代わりにCreator.create[T](otherArgs)、呼び出し構文は のようなものになりCreator.create(T, otherArgs)、大きな利点はありません (もしあれば)。しかし、後者の構文を取得することさえできません:class Aobject Aがコンパニオンの場合、それらの型は関係ありません: 最初は typeAを持ち、2 番目は type を持ちA.typeAはコンパニオン オブジェクトであり、 class のタイプではありませんA


更新:を制御できる場合に、Creator create Foo構文を機能させ、 のインスタンスを返す方法。への型引数について質問しているので、型引数について質問していると思います。これは、静的な戻り値の型を でなく にしたい場合にのみ意味があります。それ以外の場合は、質問を明確にする必要があります。FooFooAnyreifyCreator.createTAny

ここでの問題は、マクロとはほとんど関係ありません。Creator create FooはオブジェクトFooCreator.createに渡します。その宣言は、与えられFoo.typeた に型式Fooを介して型を表現する必要があります。Scala の型式は非常に制限されています。たとえば、リフレクションを使用することはできません。ただし、型を指定すると、その型メンバーを選択できます。

trait Companion[Class]
//How to declare a companion
class Foo
object Foo extends Companion[Foo]
/*I'm cheating: an implementation of Companion does not need to be a true Companion. You can add documentation to explain how Companion is supposed to be used. */
object Bar extends Companion[Foo]
//But this is also useful - you can't create your own companion objects for pre-existing types, but you can still create the right instances of Companion:
object pInt extends Companion[Int]
object Creator {
  //T with Companion[S] is needed to workaround a type inference bug (SI-5298) and allow S to be correctly inferred.
  def create[S, T <: Companion[S]](obj: T with Companion[S]): S = ???
}

コンパニオン オブジェクトを変更する必要があるため、これには制限がありますが、これ以上のことはできないと確信しています。型式S(の戻り値の型を宣言するときに の代わりに使用できるものcreate) で、コンパニオン オブジェクトから関連するクラス型に一般的に取得する方法がわかりません。

さて、マクロを使用するように上記を変更するのは簡単です:

import language.experimental.macros
import reflect.macros.Context
class Foo[T]
object Creator {
  //T with Companion[S] is needed to workaround a type inference bug (SI-5298) and allow S to be correctly inferred.
  def create[S, T <: Companion[S]](obj: T with Companion[S]): Foo[S] = macro createImpl[S, T]
  def createImpl[S: c.AbsTypeTag, T <: Companion[S]: c.AbsTypeTag](c: Context)(obj: c.Expr[T with Companion[S]]): c.Expr[Foo[S]] = {
    import c.universe._
    reify(new Foo[S]())
  }
}
于 2012-09-02T15:00:09.343 に答える