Scala 在Shapeless中,我是否可以为非case类提供一个“LabelledGeneric”实例,以实现typeclass实例的自动派生?

Scala 在Shapeless中,我是否可以为非case类提供一个“LabelledGeneric”实例,以实现typeclass实例的自动派生?,scala,code-generation,typeclass,shapeless,Scala,Code Generation,Typeclass,Shapeless,我有一个json库,它通过遵循Scala中的typeclass模式定义了ReadCodec(定义如何读取json)的概念。此库使用无形状的Typeclass构造免费为任何case类派生ReadCodec的自动实例 现在,我有了一个代码生成器,在Scala中生成的类不是case类(但可能应该是)。我可以让代码生成器为每个类生成ReadCodec实例,这就是我们现在拥有的。但是现在,如果我希望生成的类支持某种新形式的序列化,我需要修改代码生成以输出这个新类型类的实例 是否有一种方法可以修改代码生成器

我有一个json库,它通过遵循Scala中的typeclass模式定义了
ReadCodec
(定义如何读取json)的概念。此库使用无形状的
Typeclass
构造免费为任何case类派生
ReadCodec
的自动实例

现在,我有了一个代码生成器,在Scala中生成的类不是case类(但可能应该是)。我可以让代码生成器为每个类生成ReadCodec实例,这就是我们现在拥有的。但是现在,如果我希望生成的类支持某种新形式的序列化,我需要修改代码生成以输出这个新类型类的实例


是否有一种方法可以修改代码生成器,以输出带有
LabelledGeneric
实例的类,或者其他可以利用生成(通过宏)案例类自动实例的机制的方法?通过这种方式,生成的代码可以与任何类型类模式进行互操作,该模式使用无形状的“
typeclass
来具体化实例。

有一个棘手的步骤,但您肯定可以定义自己的
LabelledGeneric
实例。为了这里的示例,我将使用Alex Archambault的库,它实际上不使用
TypeClass
,但它使用
LabelledGeneric
,原理是相同的

我们班的第一名:

class Foo(val i: Int, val s: String)
那么就我们的例子来说:

import shapeless._, labelled._, record._, syntax.singleton._

implicit object fooGeneric extends LabelledGeneric[Foo] {
  val iw = Witness('i)
  val sw = Witness('s)

  type Repr = FieldType[iw.T, Int] :: FieldType[sw.T, String] :: HNil

  def from(r: Repr): Foo = new Foo(r('i), r('s))
  def to(t: Foo): Repr = ('i ->> t.i) :: ('s ->> t.s) :: HNil
}
注意,我们需要一种方法来引用
Repr
中记录键的单例类型,因此我们首先定义了几个见证人。这是棘手的部分

现在你只要写下:

import argonaut._, Argonaut._, Shapeless._
然后:

scala> implicitly[EncodeJson[Foo]].encode(new Foo(42, "foo"))
res0: argonaut.Json = {"s":"foo","i":42}

如果您愿意,我可以组合一个
LabelledTypeClass
示例,但想法完全相同。

当然,只需生成
LabelledGeneric
实例即可。有什么困难/问题?@Imm哈哈,有趣的是,我只是认为事情不会那么简单。。。我仍然希望遇到一些问题,但我想我只能试着找出答案。感谢您给我一些信心,让我相信这可能真的会起作用。@lmm定义
LabelledGeneric
实例是一个合理的问题,它不是微不足道的(因为您需要引用单例类型等)。请注意
Witness
实例现在是可有可无的,正如
Witness
现在有一个类型选择器:
type Repr=FieldType[Witness.'i`.T,Int]::FieldType[Witness.'s`.T,String]::HNil
@al3sar是的,我想我应该提到这个语法。这对我来说还是有点太神奇了。这真是太棒了!我刚刚找到时间尝试一下,经过一点修补,它成功了!