最初设计有3个类型类的软件已经发展成使用大量类型类。我们来看这个例子:
Service[A,B]
TypeClass1[A]
TypeClass2[B]
TypeClass3[A,B,C]
TypeClass4[A]
TypeClass5[B]
TypeClass6[C]
TypeClass7[C]
TypeClass8[B]
我们有6种已知的完全不相交的A,B,C组合(即每种组合包含仅在该组合中使用的A,B,C类型)。所以现在我们有两个选择:
TypeClass14[A]
,Typeclass67[C]
等等,所以最终你
最终可能会有UberTypeClass[A,B,C]
提供所有
期望的行为。第二种解决方案作为通用编程方法显然更合理:引入中间层和抽象可以通过多种方式提高代码质量。我们面临的挑战如下:
如果我们不通过提供叠加它们的隐式转换来召唤中间层的低级类型类,实际上我们只是在改进语法(但无论如何,这些都是隐含的!)但我们没有'解决代码缺少分层的问题
如果我们召集较低级别的类型类,我们最终会编写大量的中间样板(TypeClass1Instances
,TypeClass2Instances
,Typeclass3Instances
)
使用与软件分层相关的类型类时的最佳做法是什么?
答案 0 :(得分:1)
您可以使用以下内容来捆绑类型类。
您也可以使用无形的HLists将此代码推广到任意区域。
trait Lemma2[F1[_], F2[_], A] {
val F1: F1[A]
val F2: F2[A]
}
object Lemma2 {
implicit def lemma[A, F1[_], F2[_]](implicit FA: F1[A], FB: F2[A]):
Lemma2[F1, F2, A] =
new Lemma2[F1, F2, A] {
val F1 = FA
val F2 = FB
}
}
trait LemmaSyntax {
implicit def f1[F1[_], F2[_], A](implicit lemma: Lemma2[F1, F2, A]): F1[A] = {
lemma.F1
}
implicit def f2[F1[_], F2[_], A](implicit lemma: Lemma2[F1, F2, A]): F2[A] = {
lemma.F2
}
}
import cats._
import cats.implicits._
object Test extends LemmaSyntax {
type Proof[A] = Lemma2[Show, Eq, A]
def foo[A : Proof](a: A): String = {
a.show
}
}
object Other {
Test.foo("moo")
}