【发布时间】:2017-11-05 14:25:01
【问题描述】:
我仍在尝试了解 Shapeless(在较小程度上还有 Scala!),并且我一直在编写一些简单的代码来为案例类生成随机实例数据 - 主要基于此处的指南:@987654321 @(该示例涵盖了 JSON Writer 实现)
我创建了一个Generator[A] trait 并为简单类型创建了隐式实现,并且根据上面链接中的示例,我还创建了隐式实现来处理 HList、HNil、Coproduct 和 CNil:
implicit def hnilGenerator = new Generator[HNil] {
override def generate(a: HNil) = HNil
}
implicit def hconsGenerator[H, T <: HList](implicit headGen: Generator[H], tailGen: Generator[T]) =
new Generator[H :: T] {
override def generate(a: H :: T) = headGen.generate(a.head) :: tailGen.generate(a.tail)
}
implicit def cnilGenerator: Generator[CNil] =
new Generator[CNil] {
override def generate(a: CNil): CNil = throw new RuntimeException("Invalid candidate configuration")
}
implicit def cconsGenerator[H, T <: Coproduct] =
new Generator[H :+: T] {
override def generate(a: H :+: T) = throw new RuntimeException("Invalid candidate configuration")
}
我现在可以使用此代码基于案例类或密封特征生成随机实例:
it("should work with a case class to hlist") {
case class Test(x: IntGene, y: DoubleGene, z: BooleanGene)
val c = Generic[Test].to(Test(IntGene(), DoubleGene(), BooleanGene()))
generate(c)
}
it("what happens with sealed traits") {
sealed trait Shape
case class Square(width: Int, height: Int) extends Shape
case class Circle(radius: Int) extends Shape
val c = Generic[Shape].to(Circle(1))
generate(c)
}
上述两种方法都没有问题,但是,如果我尝试将其设为泛型(如在参数类型中),则会出现编译错误,无法找到必要的暗示:
it("should handle generics") {
case class GenericTest[A: Generic](x: A) {
def convert() = {
val c = Generic[A].to(x)
generate(c)
}
}
}
所以根据我的理解,因为我使用了Generic 上下文绑定A,编译器知道它将可用,所以c 必须是调用to(x) 的一些可能返回 - 我是在实现中缺少一些东西来处理来自Generic shapeless 调用的返回类型?还是我误会了什么?
我希望这是可能的,我只是错过了一些东西 - 是编译器不知道将传入什么(我假设不知道),还是有另一种可能的类型需要从中隐式处理to(x)打电话?
编辑
下面添加的编译错误 - 我真的只是想了解:是我没有满足 to(x) shapeless 调用的一些返回案例,还是因为编译器没有任何知道会传入什么,并且有些类型不适合(例如,我没有添加隐式日期生成器 - 并且案例类可能包含任何类型?我希望情况并非如此,并且作为编译器知道实际上没有任何东西被传递给它知道没有问题的类/方法?)
GeneratorSpec.scala:44: could not find implicit value for parameter gen: io.github.robhinds.genotype.Generator[GenericTest.this.evidence$1.Repr]
generate(c)
而我的 generate 方法只是一个简单的辅助方法,它得到隐含的 Generator :
def generate[A](a: A)(implicit gen: Generator[A]) = gen.generate(a)
【问题讨论】:
-
为什么需要一个值来生成另一个值?关于您的问题,您是否看过
shapeless.TypeClassCompanion,它是用来处理 ADT 的类型类的? -
粘贴编译错误可能会有用。
-
可能在代码中的某处键入推理中断,您可能希望对 Scalac 有所帮助。
-
还有,
generate()的类型签名是什么? -
@CyrilleCorpet 没有真正的理由 - 我正在考虑使用对象传递其他配置的想法(为生成的值提供约束,最大/分钟等) - 但就像我说的那样为了娱乐 :)。谢谢 - 将看看 TypeClassCompanion 代码