Scala Fundep物化及其隐含的松散类型信息
我试图使用fundep物化来增加编译时安全性。宏的返回类型取决于传递到宏中的字符串(即Foo.scala中的隐式字符串) 我的最终目标是DSL,看起来像这样Scala Fundep物化及其隐含的松散类型信息,scala,macros,scala-macros,shapeless,Scala,Macros,Scala Macros,Shapeless,我试图使用fundep物化来增加编译时安全性。宏的返回类型取决于传递到宏中的字符串(即Foo.scala中的隐式字符串) 我的最终目标是DSL,看起来像这样 "Eggs, Bacon".shoppingList.order 通过使用宏中字符串“Eggs,Bacon”生成的HList,使用order等方法具有隐式参数 我看到一些奇怪的行为 显式调用宏意味着我不能内联调用返回对象上的方法 如果我依赖于使用fundep方法的隐式转换,那么类型将被删除,并且我似乎在对类型进行强制转换,而没有显式强制转
"Eggs, Bacon".shoppingList.order
通过使用宏中字符串“Eggs,Bacon”生成的HList,使用order等方法具有隐式参数
我看到一些奇怪的行为
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) }"""
}
}
导入无形状_
导入scala.language.experimental.macros
导入scala.language.implicitConversions
导入scala.reflect.macros.whitebox
类别Foo[L
def foo:foo[L]=自我
}
对象Foo{
隐式def materialiefo[L我目前通过使用路径依赖类型来解决这个问题,这与在无形状库中使用Witness和Singleton的方式非常相似,并添加了一个类似于“shown”的方法来将我的列表转换为所需的类型。
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
}
}