我有以下
的特征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种序列转换为另一种序列。有什么相似的吗?
答案 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
请注意,T
和U
必须是单独的类型参数;使用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)
然后,合并Monoid
和Applicative
将为您提供所有zero
,append
和point
/ 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))
我不相信没有任何整理解决方案,例如一个只依赖于一个类型的类,但这个类似乎可以正常工作。