Scala 不成形在通用上下文中不起作用

Scala 不成形在通用上下文中不起作用,scala,generics,shapeless,Scala,Generics,Shapeless,我仍在努力解决Shapess(还有Scala!),我一直在编写一些简单的代码来为case类生成随机实例数据——主要基于这里的指南:(示例包括一个JSON编写器实现) 我已经创建了一个Generator[a]trait并为简单类型创建了隐式实现,根据上面链接中的示例,我还创建了隐式实现来处理HList、HNil、Coproduct和CNil: implicit def hnilGenerator = new Generator[HNil] { override def generate

我仍在努力解决Shapess(还有Scala!),我一直在编写一些简单的代码来为case类生成随机实例数据——主要基于这里的指南:(示例包括一个JSON编写器实现)

我已经创建了一个
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 handle generics") {
  case class GenericTest[A: Generic](x: A) {
    def convert() = {
      val c = Generic[A].to(x)
      generate(c)
    }
  }
}
根据我的理解,因为我使用了
Generic
上下文绑定
A
,编译器知道这将是可用的,所以
c
必须是调用
到(x)的某种可能返回
-我是否在处理
泛型
无形状调用返回类型的实现中遗漏了什么?还是我完全误解了什么

我希望这是可能的,我只是错过了一些东西-是编译器不知道将传入什么(我假设不知道),还是有另一种可能的类型需要从
到(x)
调用进行隐式处理


编辑

下面添加了编译错误-我真的只是想理解:是不是有一些从
到(x)
的无形调用的返回案例我没有考虑,还是因为编译器不知道将传入什么,并且有一些类型没有考虑(例如,我没有添加日期生成器隐式-并且case类可能包含任何类型?我希望不是这样,因为编译器知道实际上没有任何内容传递给类/方法,所以它知道没有问题?)

我的generate方法只是一个简单的helper方法,它使用隐式的
生成器

def generate[A](a: A)(implicit gen: Generator[A]) = gen.generate(a)

您的问题来自这样一个事实:
Generic
仅将case类转换为
HList
,将密封的trait转换为
Coproduct
(非递归)

因此,如果您有一个generic
generic
,您就没有关于所给的
HList
Coproduct
的信息,因此,您无法使用您的产品和Coproduct规则来查找所需的隐式。在某些显式情况下,您可能会遇到相同的问题,因此我将以此为例:

假设您有一个案例类体系结构

case class Bottom(value: String)
case class Top(bot: Bottom, count: Int)
隐式
Generic[Top]
typemyhlist=Bottom::Int::HNil
作为输出类型,因此您需要一个隐式
Generator[MyHList]
。但是由于范围中没有隐式
Generator[Bottom]
,因此无法使用
hconsgenerator

在泛型情况下,情况更糟。编译器只能推断
HList
的输出类型
generic[A]
(假设您忘记了
Coproduct
),因此您需要一个隐式
生成器[HList]
,而您无法提供它

解决方案是为具有自身可以生成的泛型的构造提供隐式表达式:

implicit def generic2generate[T, L <: HList](implicit generic: Generic.Aux[T, L], lGen: Generator[L]): Generator[T] = new Generator[T] {
  def generate(c: T) = generic.from(lGen.generate(generic.to(c)))
}

implicit def generic2generate[T,L我认为您缺少生成器类型绑定

it("should handle generics") {
  case class GenericTest[A: Generic : Generator](x: A) {
    def convert() = {
      val c = Generic[A].to(x)
      generate(c)
    }
  }
}

为什么您需要一个值来生成另一个值?关于您的问题,您是否查看了用于处理ADT的类型类的
Shapess.TypeClassCompanion
?粘贴编译错误可能会很有用。可能类型推断在代码中的某个地方中断,您可能希望对Scalac有所帮助。另外,类型是什么
generate()
?@cyrilecorpet的签名没有真正的原因-我想用对象传递其他配置(为生成的值、max/min等提供约束)-但就像我说的,这只是为了好玩:)。谢谢-将查看TypeClassCompanion代码我认为
a
不需要
生成器
typeclass(因为它应该从
泛型
中推断出来),而是它的泛型表示:
案例类GenericTest[a,Repr:Generator](x:a)(隐式val-gen:Generic.Aux[a,Repr])敬畏的,谢谢,我会看看添加这个-我做了简短的考虑,我可能要处理这个案件(TBH,原来的链接暗示它,但我认为我错了在翻译我的问题)。
implicit def generic2generate[T, L <: HList](implicit generic: Generic.Aux[T, L], lGen: Generator[L]): Generator[T] = new Generator[T] {
  def generate(c: T) = generic.from(lGen.generate(generic.to(c)))
}
it("should handle generics") {
  case class GenericTest[A: Generic : Generator](x: A) {
    def convert() = {
      val c = Generic[A].to(x)
      generate(c)
    }
  }
}