构造实现Seq的类型的空值

时间:2014-11-12 01:28:55

标签: scala scala-collections

我有以下

的特征
private class SeqConverter[T](implicit val conv : Converter[T]) extends Converter[Seq[T]] {
    def toJs(x: Seq[T]): JsAny = {
      x.foldLeft(JsArray[JsAny]()) { (acc, next) =>
        acc.+:(conv.toJs(next)) 
      }
    }
    def toScala(x: JsAny): Seq[T] = {
      val arr = x.asInstanceOf[JsArray[JsObject]]
      var lst = List[T]()
      arr foreach { x =>
        lst = conv.toScala(x) :: lst 
      }
      lst
    }
  }

我想要更像这样的东西

private class SeqConverter[T, F <: Seq[T]](implicit val conv : Converter[T]) extends Converter[F] {
    def toJs(x: F): JsAny = {
      x.foldLeft(JsArray[JsAny]()) { (acc, next) =>
        acc.+:(conv.toJs(next)) 
      }
    }
    def toScala(x: JsAny): Seq[T] = {
      //need to construct empty F here to build it
    }
  }

但问题是我无法获得F的成员以便开始预先构建它。有什么方法可以让它存在吗?似乎应该有某种方式来构造F的空成员,以便我可以使用+:以便从1种序列转换为另一种序列。有什么相似的吗?

1 个答案:

答案 0 :(得分:1)

更新:如果您想避免依赖Scalaz,您可以定义自己的类型类及其实例:

import scala.language.higherKinds

trait Coll[TS[_], T] {
  def zero: TS[T]
  def append(a: TS[T], b: TS[T]): TS[T]
  def point(x: T): TS[T]
}

object Coll {
  implicit def listOfTIsColl[T] = new Coll[List, T] {
    def zero = Nil
    def append(a: List[T], b: List[T]) = a ++ b
    def point(x: T) = List(x)
  }

  implicit def vectorOfTIsColl[T] = new Coll[Vector, T] {
    def zero = Vector.empty
    def append(a: Vector[T], b: Vector[T]) = a ++ b
    def point(x: T) = Vector(x)
  }
}

def foo[T, U, TS[_]](xs: TS[T], x: U)(implicit
  coll: Coll[TS, T],
  ev1:  TS[T] <:< Seq[T],
  ev2:  U =:= T
) = {
  (coll.zero, coll.append(coll.zero, coll.point(x)))
}

assert(foo(Vector(1, 2, 3), 4) == (Vector(), Vector(4)))
// foo(Vector(1, 2, 3), 4.4)     -- error: Cannot prove that Double =:= Int
// foo(Vector(1, 2, 3), "hello") -- error: Cannot prove that String =:= Int

请注意,TU必须是单独的类型参数;使用def foo[T, TS[_]](xs: TS[T], x: T) ...,您可以按预期使用foo,但foo(Vector(1, 2, 3), "hello")之类的内容可以使用,类型推断器会推断类似Vector[Any]的类型。然而,由于上面对foo的更严格的定义,这是不允许的,至少在惯用的功能代码中是可取的。

基于Scalaz的解决方案: Scalaz Monoid和Applicative将帮助您:

import scalaz._
import Scalaz._

scala> Monoid[List[Int]].zero
res0: List[Int] = List()

scala> Monoid[Vector[Int]].zero
res1: Vector[Int] = Vector()

scala> Monoid[Vector[Int]].append(Vector(1, 2), Vector(3, 4))
res2: Vector[Int] = Vector(1, 2, 3, 4)

scala> Applicative[Vector].point(1)
res0: Vector[Int] = Vector(1)

然后,合并MonoidApplicative将为您提供所有zeroappendpoint / pure

def foo[T, TS[_], U](xs: TS[T], x: U)(implicit
  monoid: Monoid[TS[T]],
  applic: Applicative[TS],
  ev1:    TS[T] <:< Seq[T],
  ev2:    U =:= T
) = {
  (monoid.zero, 
   monoid.append(monoid.zero, applic.point(x)))
}

然后:

> foo(Vector(1, 2, 3), 4)
res1 = (Vector(),Vector(4))

我不相信没有任何整理解决方案,例如一个只依赖于一个类型的类,但这个类似乎可以正常工作。