我正在学习Shapeless,无法解决编译错误。 我正在使用LabelledGeneric导出CoProduct实例并面临编译错误的示例。 在IDE中以及通过SBT运行时,编译都会失败。 这是一个完整的示例,因此应该只能复制粘贴此代码并轻松查看问题。
import shapeless.{ :+:, ::, CNil, Coproduct, HList, HNil, Inl, Inr, LabelledGeneric, Lazy, Witness }
import shapeless.labelled.FieldType
class DerivingCoProductInstancesWithLabelledGeneric {
sealed trait JsonValue
final case class JsonObject(fields: List[(String, JsonValue)]) extends JsonValue
final case class JsonArray(items: List[JsonValue]) extends JsonValue
final case class JsonString(value: String) extends JsonValue
final case class JsonNumber(value: Double) extends JsonValue
final case class JsonBoolean(value: Boolean) extends JsonValue
final case object JsonNull extends JsonValue
sealed trait Shape
final case class Rectangle(width: Double, height: Double) extends Shape
final case class Circle(radius: Double) extends Shape
trait JSONEncoder[A] {
def encode(value: A): JsonValue
}
//Companion object that returns a implicitly available JSONEncoder satisfying the type requirements
object JSONEncoder {
def apply[A](implicit encoder: JSONEncoder[A]): JSONEncoder[A] = encoder
}
//Make creation of JSON Encoders a little more generic by passing in the function
def createJSONEncoder[A](func: A => JsonValue): JSONEncoder[A] = new JSONEncoder[A] {
def encode(value: A) = func(value)
}
//Few instances of the type class with primitive types
implicit val jsonStringEncoder = createJSONEncoder[String](str => JsonString(str))
implicit val jsonBooleanEncoder = createJSONEncoder[Boolean](bool => JsonBoolean(bool))
implicit val jsonNumberEncoder = createJSONEncoder[Double](doubleNum => JsonNumber(doubleNum))
implicit val jsonIntEncoder = createJSONEncoder[Int](intNum => JsonNumber(intNum))
//Some combinator types
implicit def listEncoder[A](implicit enc: JSONEncoder[A]): JSONEncoder[List[A]] =
createJSONEncoder(list => JsonArray(list.map(enc.encode)))
implicit def optionEncoder[A](implicit enc: JSONEncoder[A]): JSONEncoder[Option[A]] =
createJSONEncoder(option => option.map(enc.encode).getOrElse(JsonNull))
//Now to do product derivation we would need to create encoders to represent a HList
trait JsonObjectEncoder[A] extends JSONEncoder[A] {
def encode(value: A): JsonObject
}
def createObjectEncoder[A](fn: A => JsonObject): JsonObjectEncoder[A] =
new JsonObjectEncoder[A] {
def encode(value: A): JsonObject =
fn(value)
}
//Derive defn for HNil and ::
implicit val hnilEncoder: JsonObjectEncoder[HNil] =
createObjectEncoder(hnil => JsonObject(Nil))
implicit def hlistObjectEncoder[K <: Symbol, H, T <: HList](
implicit
witness: Witness.Aux[K],
hEncoder: Lazy[JSONEncoder[H]],
tEncoder: JsonObjectEncoder[T]
): JsonObjectEncoder[FieldType[K, H] :: T] = {
val fieldName: String = witness.value.name
createObjectEncoder { hlist =>
val head = hEncoder.value.encode(hlist.head)
val tail = tEncoder.encode(hlist.tail)
JsonObject((fieldName, head) :: tail.fields)
}
}
implicit val cnilObjectEncoder: JsonObjectEncoder[CNil] =
createObjectEncoder(cnil => throw new Exception("Inconceivable!"))
implicit def coproductObjectEncoder[K <: Symbol, H, T <: Coproduct](
implicit
witness: Witness.Aux[K],
hEncoder: Lazy[JSONEncoder[H]],
tEncoder: JsonObjectEncoder[T]
): JsonObjectEncoder[FieldType[K, H] :+: T] = {
val typeName = witness.value.name
createObjectEncoder {
case Inl(h) =>
JsonObject(List(typeName -> hEncoder.value.encode(h)))
case Inr(t) =>
tEncoder.encode(t)
}
}
implicit def genericObjectEncoder[A, H <: HList](
implicit
generic: LabelledGeneric.Aux[A, H],
hEncoder: Lazy[JsonObjectEncoder[H]]
): JSONEncoder[A] =
createObjectEncoder { value =>
hEncoder.value.encode(generic.to(value))
}
val shape: Shape = Circle(1.0)
JSONEncoder[Shape]
}
答案 0 :(得分:1)
在此处删除对类型参数的限制:
implicit def genericObjectEncoder[A, H /*<: HList*/](
implicit
generic: LabelledGeneric.Aux[A, H],
hEncoder: Lazy[JsonObjectEncoder[H]]
): JSONEncoder[A] =
createObjectEncoder { value =>
hEncoder.value.encode(generic.to(value))
}
Shape
由LabelledGeneric
转换为HList
而不是副产品。