实现特定类型类的类列表 [英] List of classes implementing a certain typeclass
问题描述
我想定义一个实现公共类型类的元素的List
.例如
I would like to define a List
of elements implementing a common type class. E.g.
trait Show[A] {
def show(a: A): String
}
implicit val intCanShow: Show[Int] = new Show[Int] {
def show(int: Int): String = s"int $int"
}
implicit val stringCanShow: Show[String] = new Show[String] {
def show(str: String): String = str
}
问题是,如何定义 list = List(1, "abc")
以保证这些值的 Show
实例在范围内?然后我想将这个列表映射到像 list map {_.show}
这样的显示上.
The problem is, how to define a list = List(1, "abc")
such that it is guaranteed that a Show
instance for these values is in scope? I would then like to map this list over show like list map {_.show}
.
推荐答案
我将首先草拟一个解决方案,然后解释为什么使用 List[Any](1, "abc")
无法工作.
I will first sketch a solution, and then explain why the naive approach with List[Any](1, "abc")
cannot work.
你能做什么
定义一个包装类,可以将 A
类型的实例与 Show[A]
的实例保存在一起:
Define a wrapper class that can hold instances of type A
together with instances of Show[A]
:
case class Showable[A](a: A, showInst: Show[A]) {
def show: String = showInst.show(a)
}
将您的列表定义为List[Showable[_]]
:
var showableList: List[Showable[_]] = Nil
也许定义一个单独的方法来填充这个列表(考虑将列表本身和构建器方法打包在一个类中):
Maybe define a separate method to fill this list (consider packing the list itself and the builder-method in a class):
def addShowable[A: Show](a: A): Unit = {
showableList ::= Showable[A](a, implicitly[Show[A]])
}
或者,您可以小心地添加(范围非常窄的)隐式转换:
Alternatively, you can carefully add a (very tightly scoped) implicit conversion:
implicit def asShowable[A](a: A)(implicit s: Show[A]): Showable[A] =
Showable(a, s)
然后按如下方式构建您的列表(注意显式类型归属):
and then costruct your list as follows (note the explicit type ascription):
val showableList = List[Showable[_]](1, "abc")
现在您可以浏览列表并调用show
:
Now you can go through the list and call show
:
showableList.map(_.show)
获取String
的列表.
你不能做什么
你不能简单地定义
val list: List[Any] = List(1, "abc", <showable3>, ..., <showableN>)
然后期望能够调用show
,因为为了调用Show.show
,你需要actual Show
实例.这些东西不是一些可以在运行时擦除的类型提示,它们是实际对象,它们必须由编译器提供.一旦你创建了一个List[Any]
,所有的东西都丢失了,因为所有的类型都被合并成一个无表达的上界Any
,编译器没有办法注入所有必要的隐式 Show[T_1]
,..., Show[T_N]
.该参数与第三部分非常相似 "定义解释器时处理隐式对于我这个冗长回答的自由单子.
and then expect to be able to call show
, because in order to call Show.show
, you need actual Show
instances. These things are not some type-hints that can be erased at runtime, they are actual objects, and they must be supplied by the compiler. Once you have created a List[Any]
, all is lost, because all the types are merged into an unexpressive upper bound Any
, and the compiler has no way to inject all the necessary implicits Show[T_1]
,..., Show[T_N]
. The argument is very similar to the third section "Dealing with implicits when defining interpreter for the Free monad" of this lengthy answer of mine.
这篇关于实现特定类型类的类列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!