Generic 的隐式是如何解析的(使用 Shapeless 指南示例)?
How is an implicit of Generic resolved (using Shapeless guide example)?
我正在尝试按照出色的 Shapeless 指南学习 Shapeless。
但是在尝试这个例子时我遇到了几个绊脚石。
其中之一是 Generic[IceCream]
是如何隐式解析的。
我还没有为 Generic[IceCream] 的实例声明一个 implicit val
但它是可用的。怎么样?
代码看起来像这样,编译得很好,
import shapeless._
case class IceCream(name: String, numCherries: Int, inCone: Boolean)
case class Employee(name: String, number: Int, manager: Boolean)
trait CSVEncoder[A] {
def encode(value: A): List[String]
}
object CSVEncoder {
// "Summoner" method
def apply[A](implicit enc: CSVEncoder[A]): CSVEncoder[A] =
enc
// "Constructor" method
def instance[A](func: A => List[String]): CSVEncoder[A] =
new CSVEncoder[A] {
def encode(value: A): List[String] =
func(value)
}
}
object AdvancedShapelessUsage extends App {
//Define all typeclass instances here
def createEncoder[A](func: A => List[String]): CSVEncoder[A] =
new CSVEncoder[A] {
def encode(value: A): List[String] = func(value)
}
implicit val stringEncoder: CSVEncoder[String] =
createEncoder(str => List(str))
implicit val intEncoder: CSVEncoder[Int] =
createEncoder(num => List(num.toString))
implicit val booleanEncoder: CSVEncoder[Boolean] =
createEncoder(bool => List(if (bool) "yes" else "no"))
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)
}
implicit def genericEncoder[A, R]( //Use the Aux pattern to take out the `Repr` type
implicit gen: Generic[A] {
type Repr = R
},
enc: CSVEncoder[R]): CSVEncoder[A] = createEncoder(a => enc.encode(gen.to(a)))
val iceCreams: List[IceCream] = List(
IceCream("Sundae", 1, false),
IceCream("Cornetto", 0, true),
IceCream("Banana Split", 0, false))
def writeCsv[A](values: List[A])(implicit enc: CSVEncoder[A]): String =
values.map(value => enc.encode(value).mkString(",")).mkString("\n")
writeCsv(iceCreams)
}
当我们说implicit gen: Generic[A] {
type Repr = R
}
我认为编译器会查找 Generic[IceCream],然后引用 Repr
并将其分配给 R 类型。
我无法理解没有任何可用的 Generic[IceCream] 是如何解决的。太神奇了,我猜我不明白。
如果我没有正确理解你的问题,你想知道如何解决 Generic[IceCream]。可以解决的原因有两个:
- 任何特征 T 的隐式作用域都包括其伴生对象 T。
- Shapeless 有一个生成 Generic[T] 的宏:这个用例是名为 "implicit materializer"
的宏的常见用法
我正在尝试按照出色的 Shapeless 指南学习 Shapeless。
但是在尝试这个例子时我遇到了几个绊脚石。
其中之一是 Generic[IceCream]
是如何隐式解析的。
我还没有为 Generic[IceCream] 的实例声明一个 implicit val
但它是可用的。怎么样?
代码看起来像这样,编译得很好,
import shapeless._
case class IceCream(name: String, numCherries: Int, inCone: Boolean)
case class Employee(name: String, number: Int, manager: Boolean)
trait CSVEncoder[A] {
def encode(value: A): List[String]
}
object CSVEncoder {
// "Summoner" method
def apply[A](implicit enc: CSVEncoder[A]): CSVEncoder[A] =
enc
// "Constructor" method
def instance[A](func: A => List[String]): CSVEncoder[A] =
new CSVEncoder[A] {
def encode(value: A): List[String] =
func(value)
}
}
object AdvancedShapelessUsage extends App {
//Define all typeclass instances here
def createEncoder[A](func: A => List[String]): CSVEncoder[A] =
new CSVEncoder[A] {
def encode(value: A): List[String] = func(value)
}
implicit val stringEncoder: CSVEncoder[String] =
createEncoder(str => List(str))
implicit val intEncoder: CSVEncoder[Int] =
createEncoder(num => List(num.toString))
implicit val booleanEncoder: CSVEncoder[Boolean] =
createEncoder(bool => List(if (bool) "yes" else "no"))
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)
}
implicit def genericEncoder[A, R]( //Use the Aux pattern to take out the `Repr` type
implicit gen: Generic[A] {
type Repr = R
},
enc: CSVEncoder[R]): CSVEncoder[A] = createEncoder(a => enc.encode(gen.to(a)))
val iceCreams: List[IceCream] = List(
IceCream("Sundae", 1, false),
IceCream("Cornetto", 0, true),
IceCream("Banana Split", 0, false))
def writeCsv[A](values: List[A])(implicit enc: CSVEncoder[A]): String =
values.map(value => enc.encode(value).mkString(",")).mkString("\n")
writeCsv(iceCreams)
}
当我们说implicit gen: Generic[A] {
type Repr = R
}
我认为编译器会查找 Generic[IceCream],然后引用 Repr
并将其分配给 R 类型。
我无法理解没有任何可用的 Generic[IceCream] 是如何解决的。太神奇了,我猜我不明白。
如果我没有正确理解你的问题,你想知道如何解决 Generic[IceCream]。可以解决的原因有两个:
- 任何特征 T 的隐式作用域都包括其伴生对象 T。
- Shapeless 有一个生成 Generic[T] 的宏:这个用例是名为 "implicit materializer" 的宏的常见用法