2016-07-31 6 views
0

die folgenden von Travis Brown Bildungs- und gut geschrieben Da Type classes and generic derivation:Abweichende Implicits für Case-Klasse w/Gehäuse Klasse Argument

case class Person(name: String, age: Double) 

trait Parser[A] { 
    def apply(s: String): Option[A] 
    } 

    implicit val hnilParser: Parser[HNil] = new Parser[HNil] { 
    def apply(s: String): Option[HNil] = if(s.isEmpty) Some(HNil) else None 
    } 

    implicit def hconsParser[H: Parser, T <: HList: Parser]: Parser[H :: T] = new Parser[H :: T] { 
    def apply(s: String): Option[H :: T] = s.split(",").toList match { 
     case cell +: rest => for { 
     head <- implicitly[Parser[H]].apply(cell) 
     tail <- implicitly[Parser[T]].apply(rest.mkString(",")) 
     } yield head :: tail 
    } 
    } 

    implicit val stringParser: Parser[String] = new Parser[String] { 
    def apply(s: String): Option[String] = Some(s) 
    } 

    implicit val intParser: Parser[Int] = new Parser[Int] { 
    def apply(s: String): Option[Int] = Try(s.toInt).toOption 
    } 

    implicit val doubleParser: Parser[Double] = new Parser[Double] { 
    def apply(s: String): Option[Double] = Try(s.toDouble).toOption 
    } 

    implicit val booleanParser: Parser[Boolean] = new Parser[Boolean] { 
    def apply(s: String): Option[Boolean] = Try(s.toBoolean).toOption 
    } 

    implicit def caseClassParser[A, R <: HList](implicit gen: Generic[A] { type Repr = R }, 
               reprParser: Parser[R]): Parser[A] = 
    new Parser[A] { 
     def apply(s: String): Option[A] = reprParser.apply(s).map(gen.from) 
    } 


    object Parser { 
    def apply[A](s: String)(implicit parser: Parser[A]): Option[A] = parser(s) 
    } 

    implicit val stringParser: Parser[String] = new Parser[String] { 
    def apply(s: String): Option[String] = Some(s) 
    } 

    implicit val intParser: Parser[Int] = new Parser[Int] { 
    def apply(s: String): Option[Int] = Try(s.toInt).toOption 
    } 

    implicit val doubleParser: Parser[Double] = new Parser[Double] { 
    def apply(s: String): Option[Double] = Try(s.toDouble).toOption 
    } 

Ich war neugierig, zu versuchen, ein Parser[X] zu bekommen, wo X ein Fall-Klasse mit a Person Argument, dh einen Fall Klasse:

case class PersonWrapper(person: Person, x: Int) 

Dennoch bekomme ich einen Fehler:

scala> Parser[PersonWrapper]("kevin,66,42") 
<console>:15: error: diverging implicit expansion for type net.Test.Parser[net.Test.PersonWrapper] 
starting with method caseClassParser in object Test 
     Parser[PersonWrapper]("kevin,66,42") 
          ^

Erstens, warum tritt dieser divergente implizite Fehler auf?

Zweitens ist es möglich, den obigen Code zu verwenden, um eine Parser[PersonWrapper] zu bekommen?

+0

Sind Sie sicher, dass Sie nicht implizit im REPL-Bereich herumhängen? Ich bekomme den divergierenden impliziten Fehler nicht. –

+0

Hmm. Nun, was für ein Ergebnis hast du mit 'Parser [PersonWrapper] (" kevin, 66,42 ")? Hier ist mein vollständiges Ergebnis: https://gist.github.com/kevinmeredith/f4995cdf3bc61907bef76182bee69b39 –

Antwort

1

Secondly, is it possible to use the above code to get a Parser[PersonWrapper]?

Nein, überspringen nur bis zum Ende des Artikels:

scala> case class BookBook(b1: Book, b2: Book) 
defined class BookBook 

scala> Parser[BookBook]("Hamlet,Shakespeare") 
    res7: Option[BookBook] = None 

Our format doesn’t support any kind of nesting (at least we haven’t said anything about nesting, and it wouldn’t be trivial), so we don’t actually know how to parse a string into a BookBook...

Das Problem ist, dass cell in case cell +: rest wird immer nur ohne Komma eine Zeichenfolge sein, die implicitly[Parser[H]].apply(cell) übergeben wird. Für PersonWrapper bedeutet dies, dass die erste Zelle, dies zu tun versucht:

implicitly[Parser[PersonWrapper]].apply("kevin") 

, die offensichtlich analysieren wird fehlschlagen. Um geschachtelte Parser zum Arbeiten zu bringen, müssen Sie die Zellen gruppieren, bevor Sie ihnen einen Parser[H] zuweisen.

Verwandte Themen