如何使类型类与 Scala 中的异构列表一起使用
How to make a typeclass works with an heterogenous List in scala
给定以下类型类和一些常见类型的实例
trait Encoder[A] {
def encode(a: A): String
}
object Encoder {
implicit val stringEncoder = new Encoder[String] {
override def encode(a: String): String = a
}
implicit val intEncoder = new Encoder[Int] {
override def encode(a: Int): String = String.valueOf(a)
}
implicit def listEncoder[A: Encoder] =
new Encoder[List[A]] {
override def encode(a: List[A]): String = {
val encoder = implicitly[Encoder[A]]
a.map(encoder.encode).mkString(",")
}
}
}
有没有办法让它工作
Encoder.listEncoder.encode(List("a", 1))
如果您为 Any
定义一个实例
object Encoder {
implicit val anyEncoder = new Encoder[Any] {
override def encode(a: Any): String = a.toString
}
//instances for String, Int, List[A]
}
然后
Encoder.listEncoder[Any].encode(List("a", 1))
会起作用。
您必须在此处明确指定类型参数 (listEncoder[Any]
),因为这就是类型推断在 Scala 中的工作方式。事实上,在推断出 encode
的参数类型后
Encoder.listEncoder[???].encode(List("a", 1))
// ^^^^^^^^^^^^
// List[Any]
来不及回来推断listEncoder
的类型参数了。
如果定义委托函数
def encode[A](a: A)(implicit encoder: Encoder[A]): String = encoder.encode(a)
或语法
implicit class EncoderOps[A](a: A)(implicit encoder: Encoder[A]) {
def encode: String = encoder.encode(a)
}
// or
// implicit class EncoderOps[A](a: A) {
// def encode(implicit encoder: Encoder[A]): String = encoder.encode(a)
// }
那么您不必明确指定类型参数
encode("a")
encode(1)
encode(List("a", 1))
"a".encode
1.encode
List("a", 1).encode
顺便说一句,List("a", 1)
不是一个异构列表,它是一个元素类型为Any
的普通同构列表。 heterogenous list 将是
val l: String :: Int :: HNil = "a" :: 1 :: HNil
你可以试试magnet instead of type class
trait Magnet {
def encode(): String
}
object Magnet {
implicit def fromInt(a: Int): Magnet = new Magnet {
override def encode(): String = String.valueOf(a)
}
implicit def fromString(a: String): Magnet = new Magnet {
override def encode(): String = a
}
}
def encode(m: Magnet): String = m.encode()
encode("a")
encode(1)
List[Magnet]("a", 1).map(_.encode())
或 HList
而不是 List[A]
sealed trait HList
case class ::[+H, +T <: HList](head: H, tail: T) extends HList
case object HNil extends HList
type HNil = HNil.type
implicit class HListOps[L <: HList](l: L) {
def ::[A](a: A): A :: L = new ::(a, l)
}
trait Encoder[A] {
def encode(a: A): String
}
object Encoder {
implicit val stringEncoder: Encoder[String] = new Encoder[String] {
override def encode(a: String): String = a
}
implicit val intEncoder: Encoder[Int] = new Encoder[Int] {
override def encode(a: Int): String = String.valueOf(a)
}
implicit val hnilEncoder: Encoder[HNil] = new Encoder[HNil] {
override def encode(a: HNil): String = ""
}
implicit def hconsEncoder[H, T <: HList](implicit
hEncoder: Encoder[H],
tEncoder: Encoder[T]
): Encoder[H :: T] = new Encoder[H :: T] {
override def encode(a: H :: T): String =
s"${hEncoder.encode(a.head)},${tEncoder.encode(a.tail)}"
}
}
def encode[A](a: A)(implicit encoder: Encoder[A]): String = encoder.encode(a)
implicit class EncoderOps[A](a: A)(implicit encoder: Encoder[A]) {
def encode: String = encoder.encode(a)
}
val l: String :: Int :: HNil = "a" :: 1 :: HNil
encode(l)
l.encode
给定以下类型类和一些常见类型的实例
trait Encoder[A] {
def encode(a: A): String
}
object Encoder {
implicit val stringEncoder = new Encoder[String] {
override def encode(a: String): String = a
}
implicit val intEncoder = new Encoder[Int] {
override def encode(a: Int): String = String.valueOf(a)
}
implicit def listEncoder[A: Encoder] =
new Encoder[List[A]] {
override def encode(a: List[A]): String = {
val encoder = implicitly[Encoder[A]]
a.map(encoder.encode).mkString(",")
}
}
}
有没有办法让它工作
Encoder.listEncoder.encode(List("a", 1))
如果您为 Any
object Encoder {
implicit val anyEncoder = new Encoder[Any] {
override def encode(a: Any): String = a.toString
}
//instances for String, Int, List[A]
}
然后
Encoder.listEncoder[Any].encode(List("a", 1))
会起作用。
您必须在此处明确指定类型参数 (listEncoder[Any]
),因为这就是类型推断在 Scala 中的工作方式。事实上,在推断出 encode
的参数类型后
Encoder.listEncoder[???].encode(List("a", 1))
// ^^^^^^^^^^^^
// List[Any]
来不及回来推断listEncoder
的类型参数了。
如果定义委托函数
def encode[A](a: A)(implicit encoder: Encoder[A]): String = encoder.encode(a)
或语法
implicit class EncoderOps[A](a: A)(implicit encoder: Encoder[A]) {
def encode: String = encoder.encode(a)
}
// or
// implicit class EncoderOps[A](a: A) {
// def encode(implicit encoder: Encoder[A]): String = encoder.encode(a)
// }
那么您不必明确指定类型参数
encode("a")
encode(1)
encode(List("a", 1))
"a".encode
1.encode
List("a", 1).encode
顺便说一句,List("a", 1)
不是一个异构列表,它是一个元素类型为Any
的普通同构列表。 heterogenous list 将是
val l: String :: Int :: HNil = "a" :: 1 :: HNil
你可以试试magnet instead of type class
trait Magnet {
def encode(): String
}
object Magnet {
implicit def fromInt(a: Int): Magnet = new Magnet {
override def encode(): String = String.valueOf(a)
}
implicit def fromString(a: String): Magnet = new Magnet {
override def encode(): String = a
}
}
def encode(m: Magnet): String = m.encode()
encode("a")
encode(1)
List[Magnet]("a", 1).map(_.encode())
或 HList
而不是 List[A]
sealed trait HList
case class ::[+H, +T <: HList](head: H, tail: T) extends HList
case object HNil extends HList
type HNil = HNil.type
implicit class HListOps[L <: HList](l: L) {
def ::[A](a: A): A :: L = new ::(a, l)
}
trait Encoder[A] {
def encode(a: A): String
}
object Encoder {
implicit val stringEncoder: Encoder[String] = new Encoder[String] {
override def encode(a: String): String = a
}
implicit val intEncoder: Encoder[Int] = new Encoder[Int] {
override def encode(a: Int): String = String.valueOf(a)
}
implicit val hnilEncoder: Encoder[HNil] = new Encoder[HNil] {
override def encode(a: HNil): String = ""
}
implicit def hconsEncoder[H, T <: HList](implicit
hEncoder: Encoder[H],
tEncoder: Encoder[T]
): Encoder[H :: T] = new Encoder[H :: T] {
override def encode(a: H :: T): String =
s"${hEncoder.encode(a.head)},${tEncoder.encode(a.tail)}"
}
}
def encode[A](a: A)(implicit encoder: Encoder[A]): String = encoder.encode(a)
implicit class EncoderOps[A](a: A)(implicit encoder: Encoder[A]) {
def encode: String = encoder.encode(a)
}
val l: String :: Int :: HNil = "a" :: 1 :: HNil
encode(l)
l.encode