【问题标题】:Parametrized type alias for Bifunctors双函子的参数化类型别名
【发布时间】:2016-06-14 12:52:22
【问题描述】:

我有一个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]) 没有类型参数,预期:两个

[错误] def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {

当定义了这样的类型别名时,编译器是否会创建 2-type 暂停(可能像嵌套的 lambda 类型?)?

【问题讨论】:

    标签: scala functor scalaz type-alias bifunctor


    【解决方案1】:
    def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {  ... }
    

    上面Bifunctor中的Tuple2[...]不再有两个类型参数,因为ES都被填上了。

    例如myValBimap[Int, String] 试图创建一个Bifunctor[(Seq[Int], Seq[String])] 而类型(Seq[Int], Seq[String]) 显然没有两个类型参数。

    你可以写

    • Bifunctor[({ type λ[α, β] = (Seq[α], Seq[β])})#λ]
    • Bifunctor[λ[(α, β) => (Seq[α], Seq[β])]] 使用 kind 投影仪插件。

    如果您需要其他类型,则需要一个带有类型参数的隐式函数,可能类似于:

    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))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      相关资源
      最近更新 更多