找不到参数 enc 的隐式值:CsvEncoder[Shape]
could not find implicit value for parameter enc: CsvEncoder[Shape]
我试图理解无形的余积并有以下示例,但它不起作用:
import shapeless.{HList, ::, HNil}
import shapeless.Generic
import shapeless.{Coproduct, :+:, CNil, Inl, Inr}
trait CsvEncoder[A] {
def encode(value: A): List[String]
}
sealed trait Shape
final case class Rectangle(width: Double, height: Double) extends Shape
final case class Circle(radius: Double) extends Shape
object CsvEncoder {
def createEncoder[A](func: A => List[String]): CsvEncoder[A] = {
new CsvEncoder[A] {
override def encode(value: A): List[String] = func(value)
}
}
implicit val booleanEncoder: CsvEncoder[Boolean] =
createEncoder(value => if (value) List("yes") else List("no"))
implicit val intEncoder: CsvEncoder[Int] =
createEncoder(value => List(value.toString))
implicit val stringEncoder: CsvEncoder[String] =
createEncoder(value => List(value))
implicit val doubleEncoder: CsvEncoder[Double] =
createEncoder(value => List(value.toString))
def apply[A](implicit enc: CsvEncoder[A]): CsvEncoder[A] = enc
implicit val cnilEncoder: CsvEncoder[CNil] =
createEncoder(cnil => throw new Exception("Inconceivable!"))
implicit def coproductEncoder[H, T <: Coproduct](
implicit
hEncoder: CsvEncoder[H],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :+: T] = createEncoder {
case Inl(h) => hEncoder.encode(h)
case Inr(t) => tEncoder.encode(t)
}
def writeCsv[A](values: List[A])(implicit enc: CsvEncoder[A]): String =
values.map(value => enc.encode(value).mkString(",")).mkString("\n")
}
object Main {
def main(args: Array[String]) {
println("----------------------------------------------------------")
val shapes: List[Shape] = List(
Rectangle(3.0, 4.0),
Circle(1.0)
)
println(CsvEncoder.writeCsv(shapes))
}
}
编译器抱怨:
Error:(162, 32) could not find implicit value for parameter enc: CsvEncoder[Shape]
println(CsvEncoder.writeCsv(shapes))
Error:(162, 32) not enough arguments for method writeCsv: (implicit enc: CsvEncoder[Shape])String.
Unspecified value parameter enc.
println(CsvEncoder.writeCsv(shapes))
我是否为 Shape
创建了 CsvEncoder
的实例? Shapeless 应该为我照顾它,或者?
我会推荐 re/reading The Type Astronaut's Guide to Shapeless Book,这真是一本了不起的书。您发布的代码似乎部分来自那里。
CSV 编码器示例使用 Employee
,并手写 CsvEncoder
(第 23 页):
implicit val iceCreamEncoder: CsvEncoder[IceCream] =
new CsvEncoder[IceCream] {
def encode(i: IceCream): List[String] =
List(
i.name,
i.numCherries.toString,
if(i.inCone) "yes" else "no"
)
}
如果您不想必须手写所有这些,您将需要更多样板文件。
本书第 27 页 3.2.1 中对此进行了描述:
import shapeless.{HList, ::, HNil}
implicit val hnilEncoder: CsvEncoder[HNil] =
createEncoder(hnil => Nil)
implicit def hlistEncoder[H, T <: HList](
implicit
hEncoder: CsvEncoder[H],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :: T] =
createEncoder {
case h :: t =>
hEncoder.encode(h) ++ tEncoder.encode(t)
}
我们有递归情况,hlistEncoder
(即 returns CsvEncoder[H :: T]
),它采用头部和尾部,以及基本情况编码器,hnilEncoder
( returns CsvEncoder[HNil]
,因为 HList 的末尾总是有一个 HNil
,就像所有其他链表一样)。
然而,这足以对任何 HList 进行 CSV 编码,但是 Rectangle
不是 HList
!您需要使用 Generic
来回转换。这在本书的 3.2.2 中解释,紧接在上一部分之后(我将代码转换为使用 Generic.Aux
,这是 shapeless 最重要的工具之一):
implicit def genericEncoder[A, R](
implicit
gen: Generic.Aux[A, R],
enc: CsvEncoder[R]
): CsvEncoder[A] =
createEncoder(a => enc.encode(gen.to(a)))
gen.to
将 a
(比如 Rectangle
)转换为 HList(因此,Double :: Double :: HNil
,并对其进行编码。
它还将 Shape
转换为 Rectangle :+: Circle :+: CNil
,因此您的 Main
按原样工作:)。
我试图理解无形的余积并有以下示例,但它不起作用:
import shapeless.{HList, ::, HNil}
import shapeless.Generic
import shapeless.{Coproduct, :+:, CNil, Inl, Inr}
trait CsvEncoder[A] {
def encode(value: A): List[String]
}
sealed trait Shape
final case class Rectangle(width: Double, height: Double) extends Shape
final case class Circle(radius: Double) extends Shape
object CsvEncoder {
def createEncoder[A](func: A => List[String]): CsvEncoder[A] = {
new CsvEncoder[A] {
override def encode(value: A): List[String] = func(value)
}
}
implicit val booleanEncoder: CsvEncoder[Boolean] =
createEncoder(value => if (value) List("yes") else List("no"))
implicit val intEncoder: CsvEncoder[Int] =
createEncoder(value => List(value.toString))
implicit val stringEncoder: CsvEncoder[String] =
createEncoder(value => List(value))
implicit val doubleEncoder: CsvEncoder[Double] =
createEncoder(value => List(value.toString))
def apply[A](implicit enc: CsvEncoder[A]): CsvEncoder[A] = enc
implicit val cnilEncoder: CsvEncoder[CNil] =
createEncoder(cnil => throw new Exception("Inconceivable!"))
implicit def coproductEncoder[H, T <: Coproduct](
implicit
hEncoder: CsvEncoder[H],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :+: T] = createEncoder {
case Inl(h) => hEncoder.encode(h)
case Inr(t) => tEncoder.encode(t)
}
def writeCsv[A](values: List[A])(implicit enc: CsvEncoder[A]): String =
values.map(value => enc.encode(value).mkString(",")).mkString("\n")
}
object Main {
def main(args: Array[String]) {
println("----------------------------------------------------------")
val shapes: List[Shape] = List(
Rectangle(3.0, 4.0),
Circle(1.0)
)
println(CsvEncoder.writeCsv(shapes))
}
}
编译器抱怨:
Error:(162, 32) could not find implicit value for parameter enc: CsvEncoder[Shape]
println(CsvEncoder.writeCsv(shapes))
Error:(162, 32) not enough arguments for method writeCsv: (implicit enc: CsvEncoder[Shape])String.
Unspecified value parameter enc.
println(CsvEncoder.writeCsv(shapes))
我是否为 Shape
创建了 CsvEncoder
的实例? Shapeless 应该为我照顾它,或者?
我会推荐 re/reading The Type Astronaut's Guide to Shapeless Book,这真是一本了不起的书。您发布的代码似乎部分来自那里。
CSV 编码器示例使用 Employee
,并手写 CsvEncoder
(第 23 页):
implicit val iceCreamEncoder: CsvEncoder[IceCream] =
new CsvEncoder[IceCream] {
def encode(i: IceCream): List[String] =
List(
i.name,
i.numCherries.toString,
if(i.inCone) "yes" else "no"
)
}
如果您不想必须手写所有这些,您将需要更多样板文件。
本书第 27 页 3.2.1 中对此进行了描述:
import shapeless.{HList, ::, HNil}
implicit val hnilEncoder: CsvEncoder[HNil] =
createEncoder(hnil => Nil)
implicit def hlistEncoder[H, T <: HList](
implicit
hEncoder: CsvEncoder[H],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :: T] =
createEncoder {
case h :: t =>
hEncoder.encode(h) ++ tEncoder.encode(t)
}
我们有递归情况,hlistEncoder
(即 returns CsvEncoder[H :: T]
),它采用头部和尾部,以及基本情况编码器,hnilEncoder
( returns CsvEncoder[HNil]
,因为 HList 的末尾总是有一个 HNil
,就像所有其他链表一样)。
然而,这足以对任何 HList 进行 CSV 编码,但是 Rectangle
不是 HList
!您需要使用 Generic
来回转换。这在本书的 3.2.2 中解释,紧接在上一部分之后(我将代码转换为使用 Generic.Aux
,这是 shapeless 最重要的工具之一):
implicit def genericEncoder[A, R](
implicit
gen: Generic.Aux[A, R],
enc: CsvEncoder[R]
): CsvEncoder[A] =
createEncoder(a => enc.encode(gen.to(a)))
gen.to
将 a
(比如 Rectangle
)转换为 HList(因此,Double :: Double :: HNil
,并对其进行编码。
它还将 Shape
转换为 Rectangle :+: Circle :+: CNil
,因此您的 Main
按原样工作:)。