简化类型注释

时间:2011-01-27 09:17:03

标签: scala types

我已经创建了一个pimp方法collate,可以从任何Traversable或任何可以强制转换为可遍历的类型使用,如下例所示:

val ints = List(0,9,4,5,-3,-5,6,5,-2,1,0,6,-3,-2)
val results = ints collate {
  case i: Int if(i < 0) => i.floatValue
} andThen {
  case i: Int if(i>5) => i.toString
} andThen {
  case i: Int if(i==0) => i
} toTuple

/*
results: (List[Float], List[java.lang.String], List[Int], List[Int]) =
(List(-3.0, -5.0, -2.0, -3.0, -2.0),List(9, 6, 6),List(0, 0),List(4, 5, 5, 1))
*/

将其视为联盟'{1}}和collect的邪恶产生,如果你愿意......

它的定义如下:

partition

从概念上讲,一旦你理解了import collection.generic.CanBuildFrom class Collatable[Repr <% Traversable[T], T](xs: Repr) { // Results handling stuff, bit like a poor-man's HList, feel free to skip... trait Results { def remainder: Repr type Append[That] <: Results def append[That](tup: (That, Repr)): Append[That] def andThen[R, That](pf: PartialFunction[T, R]) (implicit matchesBuilder: CanBuildFrom[Repr, R, That], remainderBuilder: CanBuildFrom[Repr, T, Repr] ) = { val more = (new Collatable[Repr,T](remainder)).collateOne[R,That](pf) append(more) } } case class Results9[M1,M2,M3,M4,M5,M6,M7,M8,M9]( m1: M1, m2: M2, m3: M3, m4: M4, m5: M5, m6: M6, m7: M7, m8: M8, m9: M9, remainder: Repr) extends Results { implicit def toTuple = (m1, m2, m3, m4, m5, m6, m7, m8, m9, remainder) def append[That](tup: (That, Repr)) = error("too many") } // ... skip a bit, still in results logic ... case class Results2[M1,M2]( m1: M1, m2: M2, remainder: Repr) extends Results { implicit def toTuple = (m1, m2, remainder) type Append[That] = Results3[M1,M2,That] def append[That](tup: (That, Repr)) = Results3(m1, m2, tup._1, tup._2) } case class Results1[M1](matches: M1, remainder: Repr) extends Results { implicit def toTuple = (matches, remainder) type Append[That] = Results2[M1, That] def append[That](tup: (That, Repr)) = Results2(matches, tup._1, tup._2) } // and now... Our feature presentation! def collateOne[R, That](pf: PartialFunction[T, R]) (implicit matchesBuilder: CanBuildFrom[Repr, R, That], remainderBuilder: CanBuildFrom[Repr, T, Repr] ) = { val matches = matchesBuilder(xs) val remainder = remainderBuilder(xs) for (x <- xs) if (pf.isDefinedAt(x)) matches += pf(x) else remainder += x (matches.result, remainder.result) } def collate[R, That](pf: PartialFunction[T, R]) (implicit matchesBuilder: CanBuildFrom[Repr, R, That], remainderBuilder: CanBuildFrom[Repr, T, Repr] ): Results1[That] = { val tup = collateOne[R,That](pf) Results1(tup._1, tup._2) } } object Collatable { def apply[Repr, T](xs: Repr)(implicit witness: Repr => Traversable[T]) = { new Collatable[Repr, T](xs) } } implicit def traversableIsCollatable[CC[X] <: Traversable[X], A](xs: CC[A]) = Collatable[CC[A], A](xs) implicit def stringIsCollatable(xs: String) = Collatable[String, Char](xs) 的工作方式,并不是那么令人生畏,但我发现它被版画所淹没 - 尤其是涉及隐含的内容。

我知道我可以通过使用HList来大大简化ResultX逻辑,这是我可能会做的事情,所以这段代码并不特别让我担心。

我也知道如果能够将CanBuildFrom约束为Repr的子类型,我可以让我的生活显着更容易。但我拒绝这样做,因为它不能用于对抗Strings。出于同样的原因,我还想避免强制部分函数返回T的子类型 - 虽然这不是一个问题,因为我总是可以将我的逻辑分解为不同的整理和映射操作。

更多关注的是Traversable,我似乎不断重复,并且从我的方法签名中隐藏了重要的东西。这是我觉得可以在班级一次定义的东西,但我还没有找到一种方法让它发挥作用。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

只需定义类型:

class Collatable[Repr <% Traversable[T], T](xs: Repr) {

  // Results handling stuff, bit like a poor-man's HList, feel free to skip...

  type With[-Elem] = CanBuildFrom[Repr, Elem, Repr]
  type CanBuild[-Elem, +To] = CanBuildFrom[Repr, Elem, To]

  trait Results {
    def remainder: Repr

    type Append[That] <: Results
    def append[That](tup: (That, Repr)): Append[That]

    def andThen[R, That](pf: PartialFunction[T, R])
    (implicit
      matchesBuilder: CanBuild[R, That],
      remainderBuilder: With[T]
    ) = {
      val more = (new Collatable[Repr,T](remainder)).collateOne[R,That](pf)
      append(more)
    }
  }

  def collateOne[R, That](pf: PartialFunction[T, R])
  (implicit
    matchesBuilder: CanBuild[R, That],
    remainderBuilder: With[T]
  ) = { 
    val matches = matchesBuilder(xs)
    val remainder = remainderBuilder(xs)
    for (x <- xs) if (pf.isDefinedAt(x)) matches += pf(x) else remainder += x
    (matches.result, remainder.result)
  }   
}

另一方面,我刚注意到整个Collatable已在ReprT上进行参数化,那么为什么不在此处获得隐式remainderBuilder水平? 修改因为尚未推断T。现在,我不知道如何摆脱额外的暗示。