2015-11-21 2 views
1

Как упражнение, я пытаюсь посмотреть, могу ли я взять List[Any] и «отличить его» в класс case, используя бесформенный.Преобразование списка в случай Класс

Очень простой пример того, что я пытаюсь достичь:

case class Foo(i: Int, j: String) 
val foo: Option[Foo] = fromListToCaseClass[Foo](List(1:Any, "hi":Any)) 

Вот как я шейпинг мое решение (это может быть совсем выключен):

def fromListToCaseClass[CC <: Product](a: List[Any]): Option[CC] = a.toHList[???].map(x => Generic[CC].from(x)) 

Вот мои рассуждения :

Я знаю, что вы можете перейти от класса case к HList [T] (CC -> HList [T]); где T - тип HList. Я также знаю, что вы можете создать HList из списка (list -> Option [HList]), пока вы знаете тип HList. Наконец, я знаю, что вы можете перейти от HList к классу case (HList -> CC).

CC -> HList[T] 
list -> Option[HList[T]] -> Option[CC] 

Мне интересно, если это имеет смысл или я ухожу здесь. Можем ли мы сделать эту работу? Любые другие предложения? Благодаря!

ответ

5

Это может быть сделано очень прямолинейно, используя Generic и FromTraversable классы типа бесформенных в,

import scala.collection.GenTraversable 
import shapeless._, ops.traversable.FromTraversable 

class FromListToCaseClass[T] { 
    def apply[R <: HList](l: GenTraversable[_]) 
    (implicit gen: Generic.Aux[T, R], tl: FromTraversable[R]): Option[T] = 
     tl(l).map(gen.from) 
} 
def fromListToCaseClass[T] = new FromListToCaseClass[T] 

(Здесь какая-то случайная сложность из-за неудобства Scala когда речь идет о смешивании явных и предполагаемых параметров типа: мы хотим указать T явно, но для нас есть R).

Sample РЕПЛ сессия ...

scala> case class Foo(i: Int, j: String) 
defined class Foo 

scala> fromListToCaseClass[Foo](List(23, "foo")) 
res0: Option[Foo] = Some(Foo(23,foo)) 

scala> fromListToCaseClass[Foo](List(23, false)) 
res1: Option[Foo] = None 
2

Вы можете сделать это с бесформенными следующим образом:

import shapeless._ 

trait Creator[A] { def apply(list:List[Any]): Option[A] } 

object Creator { 
    def as[A](list: List[Any])(implicit c: Creator[A]): Option[A] = c(list) 

    def instance[A](parse: List[Any] => Option[A]): Creator[A] = new Creator[A] { 
    def apply(list:List[Any]): Option[A] = parse(list) 
    } 

    def arbitraryCreate[A] = instance(list => list.headOption.map(_.asInstanceOf[A])) 

    implicit val stringCreate = arbitraryCreate[String] 
    implicit val intCreate = arbitraryCreate[Int] 
    implicit val hnilCreate = instance(s => if (s.isEmpty) Some(HNil) else None) 

    implicit def hconsCreate[H: Creator, T <: HList: Creator]: Creator[H :: T] = 
instance { 
    case Nil => None 
    case list => for { 
    h <- as[H](list) 
    t <- as[T](list.tail) 
    } yield h :: t 
} 

implicit def caseClassCreate[C, R <: HList](
    implicit gen: Generic.Aux[C, R], 
    rc: Creator[R]): Creator[C] = 
    instance(s => rc(s).map(gen.from)) 
} 

И

val foo:Option[Foo] = Creator.as[Foo](List(1, "hi")) 
+3

Хорошая попытка, но вы пропустили 'Typeable' и' FromTraversable' которые имеют дело с проблемой, которую вы пытаетесь решить с 'Creator'. –

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