Bifunctors 的参数化类型别名
Parametrized type alias for Bifunctors
我有一个 Seq[R]
,我想将其拆分为一个 Tuple2[Seq[E], Seq[S]]
,在编写代码时,我想到了一个事实,即我可以为元组使用自定义 Bifunctor
seqs 和作为练习尝试编写代码:
import scalaz.Bifunctor
type MyType[E, S] = (Seq[E], Seq[S])
case class MyVali[E, S](tp: (Seq[E], Seq[S]))(implicit bifunctor: Bifunctor[MyType]) {
def bimap[C, D](f: (E) => C, g: (S) => D): (Seq[C], Seq[D]) =
bifunctor.bimap(tp)(f, g)
def leftMap[C](f: (E) => C): (Seq[C], Seq[S]) =
bifunctor.leftMap(tp)(f)
def rightMap[D](g: (S) => D): (Seq[E], Seq[D]) =
bifunctor.rightMap(tp)(g)
}
val myValBifunctorInstance = new Bifunctor[MyType] {
override def bimap[A, B, C, D](fab: (Seq[A], Seq[B]))(f: (A) => C, g: (B) => D): (Seq[C], Seq[D]) =
(fab._1.map(f), fab._2.map(g))
}
MyVali((Seq.empty[String], Seq.empty[Int]))(myValBifunctorInstance).bimap(a => a, b => b)
这很好用,但出于某种原因我不明白,我不得不声明一个参数化类型别名来编译所有这些,即 type MyType[E, S] = (Seq[E], Seq[S])
我几乎不明白为什么这有效而这不起作用:
def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {
override def bimap[A, B, C, D](fab: (A, B))(f: (A) => C, g: (B) => D): (C, D) = ???
}
[error] ... (Seq[E], Seq[S]) takes no type parameters, expected: two
[error] def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {
当定义了这样的类型别名时,编译器是否会创建 2 类型的挂起(可能像嵌套的 lambda 类型?)?
def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] { ... }
上面Bifunctor
中的Tuple2[...]
没有两个类型参数了,因为E
和S
被填入了
例如 myValBimap[Int, String]
试图创建一个 Bifunctor[(Seq[Int], Seq[String])]
并且类型 (Seq[Int], Seq[String])
显然没有两个类型参数。
你可以写
Bifunctor[({ type λ[α, β] = (Seq[α], Seq[β])})#λ]
或
Bifunctor[λ[(α, β) => (Seq[α], Seq[β])]]
使用kind projector plugin.
如果你需要一个额外的类型,你需要一个带有类型参数的隐式函数,可能是这样的:
implicit def myBimap[F[_]: Functor]: Bifunctor[λ[(α, β) => (F[α], F[β])]] = ???
一个更简单的例子是 Functor
for disjunction / \/
它使用左侧的类型参数:
implicit def functorDisj[L]: Functor[L \/ ?] = ???
implicit def functorDisj[L]: Functor[({ type λ[α] = L \/ α })#λ] = ???
关于您的原始问题:可以将您的 R
映射到 E \/ S
并使用 separate
:
import scalaz._, Scalaz._
val integers = List.range(1,10)
val stringOrInts: List[String \/ Int] =
integers.map(i => if (i % 2 == 0) i.right else i.toString.left)
stringOrInts.separate
// (List[String], List[Int]) = (List(1, 3, 5, 7, 9),List(2, 4, 6, 8))
我有一个 Seq[R]
,我想将其拆分为一个 Tuple2[Seq[E], Seq[S]]
,在编写代码时,我想到了一个事实,即我可以为元组使用自定义 Bifunctor
seqs 和作为练习尝试编写代码:
import scalaz.Bifunctor
type MyType[E, S] = (Seq[E], Seq[S])
case class MyVali[E, S](tp: (Seq[E], Seq[S]))(implicit bifunctor: Bifunctor[MyType]) {
def bimap[C, D](f: (E) => C, g: (S) => D): (Seq[C], Seq[D]) =
bifunctor.bimap(tp)(f, g)
def leftMap[C](f: (E) => C): (Seq[C], Seq[S]) =
bifunctor.leftMap(tp)(f)
def rightMap[D](g: (S) => D): (Seq[E], Seq[D]) =
bifunctor.rightMap(tp)(g)
}
val myValBifunctorInstance = new Bifunctor[MyType] {
override def bimap[A, B, C, D](fab: (Seq[A], Seq[B]))(f: (A) => C, g: (B) => D): (Seq[C], Seq[D]) =
(fab._1.map(f), fab._2.map(g))
}
MyVali((Seq.empty[String], Seq.empty[Int]))(myValBifunctorInstance).bimap(a => a, b => b)
这很好用,但出于某种原因我不明白,我不得不声明一个参数化类型别名来编译所有这些,即 type MyType[E, S] = (Seq[E], Seq[S])
我几乎不明白为什么这有效而这不起作用:
def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {
override def bimap[A, B, C, D](fab: (A, B))(f: (A) => C, g: (B) => D): (C, D) = ???
}
[error] ... (Seq[E], Seq[S]) takes no type parameters, expected: two
[error] def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {
当定义了这样的类型别名时,编译器是否会创建 2 类型的挂起(可能像嵌套的 lambda 类型?)?
def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] { ... }
上面Bifunctor
中的Tuple2[...]
没有两个类型参数了,因为E
和S
被填入了
例如 myValBimap[Int, String]
试图创建一个 Bifunctor[(Seq[Int], Seq[String])]
并且类型 (Seq[Int], Seq[String])
显然没有两个类型参数。
你可以写
Bifunctor[({ type λ[α, β] = (Seq[α], Seq[β])})#λ]
或Bifunctor[λ[(α, β) => (Seq[α], Seq[β])]]
使用kind projector plugin.
如果你需要一个额外的类型,你需要一个带有类型参数的隐式函数,可能是这样的:
implicit def myBimap[F[_]: Functor]: Bifunctor[λ[(α, β) => (F[α], F[β])]] = ???
一个更简单的例子是 Functor
for disjunction / \/
它使用左侧的类型参数:
implicit def functorDisj[L]: Functor[L \/ ?] = ???
implicit def functorDisj[L]: Functor[({ type λ[α] = L \/ α })#λ] = ???
关于您的原始问题:可以将您的 R
映射到 E \/ S
并使用 separate
:
import scalaz._, Scalaz._
val integers = List.range(1,10)
val stringOrInts: List[String \/ Int] =
integers.map(i => if (i % 2 == 0) i.right else i.toString.left)
stringOrInts.separate
// (List[String], List[Int]) = (List(1, 3, 5, 7, 9),List(2, 4, 6, 8))