问题
Assuming that a class Thing
is defined, and an operation +
is associated with a type class:
trait TypeClass[X, Y] {
type Out
def v: Out
}
object TypeClass {
implicit def summon[X <: Int, Y <: Int]: TypeClass[X, Y] = new TypeClass[X, Y] {
type Out = Int
override def v: Out = 2
}
}
case class Thing[X]() {
def +[Y](that: Thing[Y])(implicit typeClass: TypeClass[X, Y]): typeClass.Out = typeClass.v
}
Now if I want to define a shortcut function +2x
, which represents X + Y + Y
. My first instinct was to introduce an implicit parameter:
def ++[Y, Z](that: Thing[Y])(implicit t1: TypeClass[X, Y] { type Out <: Z }, t2: TypeClass[Z, Y]): t2.Out = t2.v
But then t2 becomes an impossible shoe to fill:
assert(Thing(1) + Thing(2) == Thing(2)) // works fine
assert(Thing(1) ++ Thing(2) == Thing(2)) // TypeClass.scala:34: could not find implicit value for parameter t2: TypeClass.this.TypeClass[Z,Int]
I could also use a more intuitive format:
def +++[Y, Z](that: Thing[Y])(implicit t1: TypeClass[X, Y] { type Out <: Y }, a: Any = this + that + that): a.type =
a
unfortunately implicit t1 cannot be made visible to the expression that defines the result:
TypeClass.scala:29: type mismatch;
found : a.type (with underlying type Any)
required: AnyRef
so what is the easiest, most intuitive way to define this?
Thanks a lot for your opinion
回答1:
You lost type refinement. Replace
implicit def summon[X <: Int, Y <: Int]: TypeClass[X, Y] = new TypeClass[X, Y] {...
with
implicit def summon[X <: Int, Y <: Int]: TypeClass[X, Y] {type Out = Int} = new TypeClass[X, Y] {...
I guess case class Thing[X]()
should be case class Thing[X](x: X)
. Then
assert(Thing(1) + Thing(2) == 2)
assert(Thing(1) ++ Thing(2) == 2)
work.
How to debug implicits: In scala 2 or 3, is it possible to debug implicit resolution process in runtime?
来源:https://stackoverflow.com/questions/62399395/in-scala-what-is-the-easiest-way-to-chain-functions-defined-with-a-type-class-a