In scala, how to make type class working for Aux pattern?

非 Y 不嫁゛ 提交于 2021-01-25 07:18:09

问题


Here is a simple example:

  trait Base {

    type Out
    def v: Out
  }

  object Base {

    type Aux[T] = Base { type Out = T }

    class ForH() extends Base {

      type Out = HNil

      override def v: Out = HNil
    }

    object ForH extends ForH
  }

  class TypeClass[B]

  trait TypeClassLevel1 {

    def summon[B](b: B)(implicit ev: TypeClass[B]): TypeClass[B] = ev
  }

  object TypeClass extends TypeClassLevel1 {

    implicit def t1: TypeClass[Base.Aux[HNil]] = new TypeClass[Base.Aux[HNil]]

    implicit def t2: TypeClass[Int] = new TypeClass[Int]
  }

  it("No Aux") {

    val v = 2

    TypeClass.summon(v) // works
  }


  it("Aux") {

    val v = new Base.ForH()

    TypeClass.summon(v) // oops
    TypeClass.summon(Base.ForH) // oops

    val v2 = new Base.ForH(): Base.Aux[HNil]
    TypeClass.summon(v2) // works!
  }

The object Base/ForH clearly has a stable path, this eliminate the possibility of the compiler not being able to resolve type ForH.Out.

What bothers me is not how incapable the compiler is to figure out the fact that ForH <:< Aux[HNil], but how easy it is to patch it up, just by a simple type upcast (last 2 lines). IMHO both features (type lambda & type classes) are important aspect of functional programming, why they can't work together at the same time?

If you are familiar with the compiler design I'll have an extra question: what does it take to improve the type class search algorithm to make it happen? Thanks a lot for your opinion.

UPDATE 1: a specific fix has been proposed but I have another problem trying to generalise it, please see In scala, how to make type class working for Aux pattern? - Part 2 for detail


回答1:


So the compiler is able to infer ForH <:< Aux[HNil], but (tbh I don't know exactly why) when resolving an implicit when the return type uses a type lambda, it gets confused if you don't use a type bound.

Anyway that's probably not a great explanation, but at least I can make your code compile. Just change t1 to:

implicit def t1[T <: Base.Aux[HNil] ]: TypeClass[T] = new TypeClass[T]

this works for me in scastie using Scala 2.13.4.



来源:https://stackoverflow.com/questions/65838535/in-scala-how-to-make-type-class-working-for-aux-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!