我很难为提出一个好的心理模型,当一个问题非常适合Type Classes模式时?
最近我正在使用像
这样的模型sealed trait FooBar
case class Foo() extends FooBar
case class Bar() extends FooBar
直观地说,我只是模式匹配
def handle(x: FooBar) = x match {
case f: Foo => println("foo")
case b: Bar => println("bar")
}
或明确使用子类型/重载
object Overloading {
def handle(x: Foo) = println("foo")
def handle(x: Bar) = println("bar")
}
另一方面,类型类方法很冗长,我认为使用它没有任何好处:
trait FooBarThing[T <: FooBar] {
def handle(x: T): Unit
}
object TypeClass {
implicit object HandleFoo extends FooBarThing[Foo] {
def handle(x: Foo) = println("foo")
}
implicit object HandleBar extends FooBarThing[Bar] {
def handle(x: Bar) = println("bar")
}
def process[T <: FooBar](x: T)(implicit ev: FooBarThing[T]): Unit = {
ev.handle(x)
}
}
我发现很多文章解释了如何来编写类型类,但在 时没有太多?
答案 0 :(得分:2)
Typeclass模式提供了实现 ad-hoc多态的可能性。
也就是说,如果你有一些多态函数foobar
,它必须使用许多不同的类型T
,然后你有一些具体的类型T1
,它没有实现任何提供{{{1}的接口。 1}},您可以按照以下方式将foobar
附加到foobar
:
T1
在上面的例子中,您可以看到两件事:
trait FoobarTypeclass[T] {
def foobar(t: T): Unit
}
def functionThatRequiresFoobar[T: FoobarTypeclass](t: T): Unit = {
for (i <- 1 to 10)
implicitly[FoobarTypeclass[T]].foobar(t)
}
// note that `functionThatRequiresFoobar` knows nothing about `T1` at this point
class T1
implicit object AdHocFoobarForT1 extends FoobarTypeclass[T1] {
def foobar(t: T1): Unit = println("foobar now works on T1, awesome!")
}
functionThatRequiresFoobar(new T1) // but here, it works anyway!
和FoobarTypeclass
都不知道具体类型functionThatRequiresFoobar
T1
类型还必须对T1
或FoobarTypeclass
一无所知。这意味着,functionThatRequiresFoobar
和T1
完全解耦。但是在示例的最后一行,
functionThatRequiresFoobar
无论如何,工作得很好,因为functionThatRequiresFoobar(new T1)
类型类以特别的方式将AdHocFoobarForT1
的实现附加到类foobar
。
类似地,您可以使用此模式以特定方式实现接口&#34;在未在其继承层次结构中声明任何相关接口的类上。这反过来允许您将完全独立的库粘合在一起,只需在此处提供一些类型类。
答案 1 :(得分:0)
Andrey Tyukin已经回答了你何时可以使用类型类,所以我只想添加为什么在FooBar
是密封类型或者你不需要 ad-hoc多态时更喜欢模式匹配而不是重载。
通常,重载会给类型系统带来很多麻烦,并且使得implicits的使用更加困难。 Question on SO讨论了重载的其他缺点,但其中包括:
我只会在为未连接类型提供相同功能的情况下使用重载,以创建更好的程序员体验,例如。
object Printer {
def print(a: Bool): String = ???
def print(a: Int): String = ???
}
由于您可以对子类型进行模式匹配,因此我肯定会使用该选项。