我正在尝试使用fundep实现来增加编译时的安全性。宏的返回类型取决于传递给宏的字符串(即隐含在Foo.scala中)。
我的最终目标是看起来像这样的DSL,
"Eggs, Bacon".shoppingList.order
使用HList命令具有隐式参数的方法,该HList由宏中的字符串“Eggs,Bacon”生成。
我看到了一些奇怪的行为,
Foo.scala有简化的宏,FooExample.scala有奇怪的行为。
有没有这样做?
Foo.scala
import shapeless._
import scala.language.experimental.macros
import scala.language.implicitConversions
import scala.reflect.macros.whitebox
class Foo[L <: HList](val list: L) { self =>
def foo: Foo[L] = self
}
object Foo {
implicit def materializeFoo[L <: HList](foo: String): Foo[L] = macro FooMacro.materialize_foo_impl[L]
}
object FooMacro {
def materialize_foo_impl[L <: HList : c.WeakTypeTag](c: whitebox.Context)(foo: c.Expr[String]): c.Tree = {
import c.universe._
q"""{ new Foo($foo :: HNil) }"""
}
}
FooExample.scala
import shapeless._
import shapeless.test._
import Foo._
final class Bar[L <: HList](foo: Foo[L]) {
def bar: L = foo.list
}
object FooExample {
implicit def foo2Bar[L <: HList](foo: Foo[L]): Bar[L] = new Bar(foo)
def main(args: Array[String]) {
val expected = "test" :: HNil
val notExpected = HNil
val f1 = Foo.materializeFoo("test")
sameTyped(expected)(f1.list)
val f2 = "test".foo
sameTyped(f2.list)(expected)
sameTyped(f2.list)(notExpected)
val l1: String :: HNil = f2.list
//This actually compiles but throws a ClassCastException
//val l2: HNil = f2.list
illTyped("""Foo.materializeFoo("test").list""")
sameTyped(expected)("test".foo.list)
sameTyped(notExpected)("test".foo.list)
sameTyped(expected)(f1.bar)
illTyped("""Foo.materializeFoo("test").bar""")
//I actually just want to call "test".foo.bar and have bar have the correct type
}
}