List of classes implementing a certain typeclass

后端 未结 4 938
陌清茗
陌清茗 2021-02-15 11:02

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 int         


        
4条回答
  •  感情败类
    2021-02-15 11:28

    I will first sketch a solution, and then explain why the naive approach with List[Any](1, "abc") cannot work.


    What you can do

    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)
    }
    

    Define your list as 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")
    

    Now you can go through the list and call show:

    showableList.map(_.show)
    

    to obtain a list of String.


    What you cannot do

    You cannot simply define

    val list: List[Any] = List(1, "abc", , ..., )
    

    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.

提交回复
热议问题