2014-11-12 3 views
2

У меня есть черта, как следующийпостроение пустого значения типа, который реализует Seq

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

какая библиотека Json это используется? –

+0

Кстати, почему это связано с циклом с 'var', а не просто' arr.map (conv.toScala) '? –

+0

Im используя scala js не библиотеку json. JsArray не имеет карты, которая имеет правильный тип для причин JavaScript. Теперь, когда я смотрю, возможно, это возможно сделать с разницей, но не могу использовать карту – Jake

ответ

1

UPDATE: если вы хотите, чтобы избежать зависимости от 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"), будут работать, и тип inferencer будет вызывать тип Vector[Any]. Однако, с вышесказанным, более строгим определением foo, это не будет разрешено, то есть, по крайней мере, в идиоматическом функциональном коде желательно.

Scalaz решение на основе: Scalaz Monoid и Аппликативный поможет:

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

Я не уверен, что нет никаких conciser растворы, например, который полагается только на один тип класса, но этот, похоже, работает правильно.

+0

Это то, что я буду считать наверняка, но я надеялся на способ сделать это в стандартной библиотеке. Если нет, я думаю, что эта идея будет работоспособной, если я просто сделаю то, что мне нужно сама. Проблема в том, что на самом деле это происходит в коде, который я генерирую, чтобы добавить другие проекты, поэтому добавление нестандартной библиотеки заставит их использовать это. Я действительно хочу, чтобы это было plug and play. – Jake

+0

Я добавил пример с классом пользовательского типа 'Coll [TS [_], T]' и экземплярами его, но почему вы все равно генерируете код? –

Смежные вопросы