您似乎混淆了几个不同的概念。Iso、隐式转换和宏都彼此完全不同。
我们当然可以为参数化类型定义一个等价的 Iso,尽管语法变得有点麻烦:
import scalaz._, Scalaz._
case class BiIso[F[_, _], G[_, _]](left: F ~~> G,
right: G ~~> F)
type PairList[A, B] = List[(A, B)]
val listToMap = new (PairList ~~> Map) {
def apply[A, B](l: PairList[A, B]) = l.toMap
}
val mapToList = new (Map ~~> PairList) {
def apply[A, B](m: Map[A, B]) = m.toList
}
val listMapIso = BiIso(listToMap, mapToList)
我们当然可以隐含其中的一部分,尽管这是一个正交的问题。我们可以隐式构建 BiIso:
implicit val listToMap = new (PairList ~~> Map) {
def apply[A, B](l: PairList[A, B]) = l.toMap
}
implicit val mapToList = new (Map ~~> PairList) {
def apply[A, B](m: Map[A, B]) = m.toList
}
implicit def biIso[F[_, _], G[_, _]](implicit left: F ~~> G, right: G ~~> F) =
BiIso(left, right)
implicitly[BiIso[PairList, Map]]
我们可以让任何 BiIso 充当隐式转换,尽管我不建议这样做。唯一棘手的部分是正确引导类型推断。这是大部分的方式,但由于某种原因,没有推断出 GAB 参数(非常欢迎进行更正):
sealed trait BiAny[F[_, _]] {}
object BiAny {
implicit def any[F[_, _]] = new BiAny[F] {}
}
sealed trait ApplyBiIso[FAB, GAB] {
type A1
type B1
type F[_, _]
type G[_, _]
type Required = BiIso[F, G]
val unapplyL: Unapply2[BiAny, FAB] {
type A = A1; type B = B1;
type M[C, D] = F[C, D]
}
val unapplyR: Unapply2[BiAny, GAB] {
type A = A1; type B = B1;
type M[C, D] = G[C, D]
}
def liftBI(bi: Required): Iso[FAB, GAB] =
Iso({ fab: FAB =>
val f: F[A1, B1] = Leibniz.witness(unapplyL.leibniz)(fab)
val g: G[A1, B1] = bi.left(f)
Leibniz.witness(Leibniz.symm[⊥, ⊤, GAB, G[A1, B1]](unapplyR.leibniz))(g): GAB
},
{ gab: GAB =>
val g: G[A1, B1] = Leibniz.witness(unapplyR.leibniz)(gab)
val f: F[A1, B1] = bi.right(g)
Leibniz.witness(Leibniz.symm[⊥, ⊤, FAB, F[A1, B1]](unapplyL.leibniz))(f): FAB
}
)
}
object ApplyBiIso {
implicit def forFG[FAB, A2, B2, GAB, A3, B3](
implicit u1: Unapply2[BiAny, FAB] { type A = A2; type B = B2 },
u2: Unapply2[BiAny, GAB] { type A = A3; type B = B3 }) = new ApplyBiIso[FAB, GAB] {
type A1 = A2
type B1 = B2
type F[C, D] = u1.M[C, D]
type G[C, D] = u2.M[C, D]
//Should do the conversion properly with Leibniz but I can't be bothered
val unapplyL = u1.asInstanceOf[Unapply2[BiAny, FAB] {
type A = A1; type B = B1;
type M[C, D] = F[C, D]
}]
val unapplyR = u2.asInstanceOf[Unapply2[BiAny, GAB] {
type A = A1; type B = B1;
type M[C, D] = G[C, D]
}]
}
type Aux[FAB, GAB, Required1] = ApplyBiIso[FAB, GAB] { type Required = Required1 }
def apply[FAB, GAB](implicit abi: ApplyBiIso[FAB, GAB]): Aux[FAB, GAB, abi.Required] = abi
}
sealed trait AppliedBiIso[FAB, GAB] {
val iso: Iso[FAB, GAB]
}
object AppliedBiIso {
implicit def applyAndIso[FAB, GAB, Required1](
implicit ap: ApplyBiIso.Aux[FAB, GAB, Required1],
iso1: Required1) = new AppliedBiIso[FAB, GAB] {
//Should do the conversion properly with Leibniz but I can't be bothered
val iso = ap.liftBI(iso1.asInstanceOf[BiIso[ap.F, ap.G]])
}
}
implicit def biIsoConvert[FAB, GAB](
f: FAB)(implicit ap: AppliedBiIso[FAB, GAB]): GAB =
ap.iso.left(f)
val map: Map[String, Int] = Map("Hello" -> 4)
val list: PairList[String, Int] =
biIsoConvert[Map[String, Int], PairList[String, Int]](map)
我毫不怀疑有可能使这项工作正常进行。
这仍然留下了宏,这又是一个或多或少正交的问题。我可以看到它们可能相关的一个地方是,如果不使用宏就不可能在 scala 中抽象过度种类。您是否想要适用于任何“形状”的等效 Iso,而不仅仅是F[_, _]
?对于宏来说,这将是一个很好的用例——尽管在我不羡慕任何试图实现它的人之前编写了这种宏。