实现特定类型类的类列表 [英] List of classes implementing a certain typeclass

查看:41
本文介绍了实现特定类型类的类列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想定义一个实现公共类型类的元素的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆