我有以下情况,考虑到两种类型的MA和MB,我希望能够证明它们不仅有一个Applicative,而且它们都具有相同的底层形状。我试着做以下几件事:
type UnapplyM[TC[_[_]], MA, M0[_]] = Unapply[TC, MA]{ type M[X] = M0[X] }
implicit def thing[MA, MB, M[_]](implicit un: UnapplyM[Applicative,MA,M], un2: UnapplyM[Applicative,MB,M]) = ...但是,不断地陷入分歧意味着(也就是说,这是行不通的)。类似的事情可以通过Unapply和work的Unapply类型param上的类型投影来完成。
这有一种方法可以接受这两种类型,并能够证明它们实际上是由相同类型的类实例支持的吗?
发布于 2016-03-07 14:39:19
首先,我要说,一个完整的答案将是一个很长的故事,我从去年夏天就讲了其中的很大一部分,所以我将略过这里的一些细节,只提供thing for Cats的一个工作实现。
另一个介绍性说明:这种机器现在存在于Scalaz中,some of the "review" on my pull request补充说,我很高兴猫的存在有很多原因。:)
首先,对于一个完全不透明的类型类,我甚至不会尝试在这里激发:
case class SingletonOf[T, U <: { type A; type M[_] }](
widen: T { type A = U#A; type M[x] = U#M[x] }
)
object SingletonOf {
implicit def mkSingletonOf[T <: { type A; type M[_] }](implicit
t: T
): SingletonOf[T, t.type] = SingletonOf(t)
}接下来,我们可以定义一个IsoFunctor,因为猫目前似乎还没有:
import cats.arrow.NaturalTransformation
trait IsoFunctor[F[_], G[_]] {
def to: NaturalTransformation[F, G]
def from: NaturalTransformation[G, F]
}
object IsoFunctor {
implicit def isoNaturalRefl[F[_]]: IsoFunctor[F, F] = new IsoFunctor[F, F] {
def to: NaturalTransformation[F, F] = NaturalTransformation.id[F]
def from: NaturalTransformation[F, F] = to
}
}我们可能需要一些比IsoFunctor更简单的东西来完成我们将要做的事情,但是它是一个很好的原则性类型类,也是我在Scalaz中使用的类,所以我将在这里继续使用它。
接下来,一个新的Unapply将两个Unapply实例捆绑在一起:
import cats.Unapply
trait UnapplyProduct[TC[_[_]], MA, MB] {
type M[X]; type A; type B
def TC: TC[M]
type MA_ = MA
def _1(ma: MA): M[A]
def _2(mb: MB): M[B]
}
object UnapplyProduct {
implicit def unapplyProduct[
TC[_[_]], MA0, MB0,
U1 <: { type A; type M[_] },
U2 <: { type A; type M[_] }
](implicit
sU1: SingletonOf[Unapply[TC, MA0], U1],
sU2: SingletonOf[Unapply[TC, MB0], U2],
iso: IsoFunctor[U1#M, U2#M]
): UnapplyProduct[TC, MA0, MB0] {
type M[x] = U1#M[x]; type A = U1#A; type B = U2#A
} = new UnapplyProduct[TC, MA0, MB0] {
type M[x] = U1#M[x]; type A = U1#A; type B = U2#A
def TC = sU1.widen.TC
def _1(ma: MA0): M[A] = sU1.widen.subst(ma)
def _2(mb: MB0): M[B] = iso.from(sU2.widen.subst(mb))
}
}历史上的一点是,UnapplyProduct在Scalaz中存在了四年,之后它才有了任何有用的实例。
现在我们可以写这样的东西:
import cats.Applicative
def thing[MA, MB](ma: MA, mb: MB)(implicit
un: UnapplyProduct[Applicative, MA, MB]
): Applicative[un.M] = un.TC然后:
scala> import cats.data.Xor
import cats.data.Xor
scala> thing(Xor.left[String, Int]("foo"), Xor.right[String, Char]('a'))
res0: cats.Applicative[[x]cats.data.Xor[String,x]] = cats.data.XorInstances$$anon$1@70ed21e4我们成功地说服编译器识别如何分解这些Xor类型,以便它能够看到相关的Applicative实例(我们返回)。
https://stackoverflow.com/questions/35845572
复制相似问题