Scala Typeclass具有多个参数错误
我遇到了一个奇怪的错误,与这个多参数typeclass实现中的类型有关Scala Typeclass具有多个参数错误,scala,types,functional-programming,typeclass,Scala,Types,Functional Programming,Typeclass,我遇到了一个奇怪的错误,与这个多参数typeclass实现中的类型有关 trait Feedtype trait Atom extends Feedtype trait Rss2 extends Feedtype case object Atom extends Atom case object Rss2 extends Rss2 trait Encoding trait Xml extends Encoding trait Json case object Json extends Json
trait Feedtype
trait Atom extends Feedtype
trait Rss2 extends Feedtype
case object Atom extends Atom
case object Rss2 extends Rss2
trait Encoding
trait Xml extends Encoding
trait Json
case object Json extends Json
case object Xml extends Xml
trait Content
case class show[T <: Feedtype,E <: Encoding](str: String, tp: T, en: E) extends Content
trait TypeClass[C,D,E] {
def show(c: C, d: D, e:E): String
}
trait Service{
def print[T,C,D](t: T,c:C, d:D)(implicit s: TypeClass[T,C,D]): String
}
object Service extends Service{
def print[T,C,D](t:T, c:C, d:D)(implicit s: TypeClass[T,C,D]): String =
s.show(t,c,d)
}
implicit val t1 = new TypeClass[show[Atom,Xml], Atom, Xml] {
def show(c: show[Atom,Xml], d:Atom, e:Xml) = c.str
}
implicit val t2 = new TypeClass[show[Rss2,Xml], Rss2, Xml] {
def show(c: show[Rss2,Xml], d:Rss2, e:Xml) = "hi there " + c.str
}
val s1 = show("some show", Atom, new Xml {})
Service.print(s1, s1.tp, s1.en)
我错过了什么
更新
我发现问题在于
atom
和xml
在被用作创建s1
的值时是case对象。如果我使用newatom{}
或newxml{}
则执行正常。但是,我想知道为什么案例对象被认为是与它们所代表的类型不同的类型?正如已经指出的,问题在于:
val s1 = show("some show", Atom, new Xml {})
// ^
// The most specific type of this is Atom.type
Service#print
的类型参数由传递给它的对象推断s1
是一个show[Atom.type,Xml]
,因此编译器正在为服务#打印
寻找一个隐式TypeClass[show[Atom.type,Xml],Atom.type,Xml]
。编译器不会自动尝试将Atom.type
(强制转换对象)向上转换为Atom
,原因如下:
编译器不知道show[Atom.type,Xml]
也是show[Atom,Xml]
(show
声明为不变量,TypeClass
也是不变量)
有一个隐式TypeClass[show[Atom,Xml],Atom,Xml]
可用于泛型Atom
,但不适用于更具体的类型Atom.type
你的例子很复杂,但不需要是复制问题。考虑这一点:
trait TypeClass[A] {
def show(a: A): String
}
trait Atom
case object Atom extends Atom
implicit val ar = new TypeClass[Atom] {
def show(a: Atom): String = "Atom"
}
object Service {
def print[A](a: A)(implicit tc: TypeClass[A]) = tc.show(a)
}
scala> Service.print(Atom)
<console>:18: error: could not find implicit value for parameter tc: TypeClass[Atom.type]
Service.print(Atom)
^
这将允许隐式表达式立即解析。如果您想保持TypeClass
不变,我们可以自己向上投射Atom
:
scala> Service.print(Atom: Atom)
res4: String = Atom
如何将此应用于您的示例
最简单的方法是向上投射原子:
val s1 = show("some show", Atom: Atom, new Xml {})
或,显示
和类型类
不能是不变的。首先,使show
在T
上协变,这样ashow[Atom.type,B]
也是show[Atom,B]
:
case class show[+T <: Feedtype, E <: Encoding](str: String, tp: T, en: E) extends Content
什么是原子?请发布您的问题的详细信息。缺少部分代码,请立即修复。抱歉和感谢对于这个详细的回答,我非常感激。谢谢。
val s1 = show("some show", Atom: Atom, new Xml {})
case class show[+T <: Feedtype, E <: Encoding](str: String, tp: T, en: E) extends Content
trait TypeClass[-C, -D, E] {
def show(c: C, d: D, e:E): String
}
// cutting out putting it all together to save space
scala> val s1 = show("some show", Atom, new Xml {})
s1: show[Atom.type,Xml] = show(some show,Atom,$anon$1@76a4d6c)
scala> Service.print(s1, s1.tp, s1.en)
res1: String = some show