2016-04-19 17 views
9

Ich beobachte eine sehr seltsame Art Fehler mit shapeless.everywhere. Betrachten Sie den folgenden Ammoniten-Skript, das mit load.module fein lädt:Strange type Fehler nach "inline" ein val

load.ivy("com.chuusai" %% "shapeless" % "2.3.0") 

@ 

import shapeless._ 
import poly._ 

final case class Person(name: Person.Name, age: Person.Age) 

object Person { 
    final case class Name(value: String) extends AnyVal 
    final case class Age(value: Int) extends AnyVal 
} 

def happyBirthday(person: Person, howManyYearsPast: Int): Person = { 
    object incAge extends ->((age: Int) => age + howManyYearsPast) 
    // THE MAGIC VAL 
    val oldPerson = everywhere(incAge)(person) 
    oldPerson 
} 

val john = Person(Person.Name("John Doe"), Person.Age(42)) 

val oldJohn = happyBirthday(john, 30) 

Nun, wenn ich die MAGIC VAL in diesem Skript zu „inline“ versuchen, das heißt die val mit nur everywhere(incAge)(person) ersetzen, erhalte ich den folgende Art Fehler aus dem Nichts:

Main.scala:50: type mismatch; 
found : person.type (with underlying type cachef6f1545a8d4dc31cb54d9957675f0559.Person) 
required: shapeless.poly.Case[_1.type,shapeless.HNil]{type Result = ?} where val _1: shapeless.EverywhereAux[incAge.type] 
    everywhere(incAge)(person) 

WAT?

Ich denke, es gibt scalac schwarze Magie implizite Auflösung zu beschuldigen, aber kann mir nicht einen Sinn dessen, was hier vorgeht. Es wäre großartig (und definitiv etwas aufschlussreich für mich), wenn jemand mir dieses Geheimnis enthüllen könnte.

Dank

+0

Erhalten Sie das gleiche Ergebnis beim Kompilieren als Quelldatei mit scalac oder nur auf der REPL (Ammonit oder anders)? –

+0

@MilesSabin Nun, ich habe dieses erfundene Beispiel mit scalac tbh nicht versucht. Aber es ist eine abgespeckte Version eines echten Problems in unserem Code, also nehme ich an, dass es auch mit scalac scheitern wird. Ich werde morgen Scalac versuchen. – lunaryorn

Antwort

4

Ich weiß nicht, den realen Grund für dieses Problem, aber es wird durch den erwarteten Typen Beeinflussung implizite Suche und Typinferenz verursacht. Sie können die nicht-inlined machen Version kompilieren nicht durch eine zu erwartende Art zu schaffen:

def happyBirthday(person: Person, howManyYearsPast: Int): Person = { 
    object incAge extends ->((age: Int) => age + howManyYearsPast) 
    val oldPerson: Person = everywhere(incAge)(person) 
    oldPerson 
} 

Diese mit der exakt gleichen Fehler fehlschlägt.

def happyBirthday(person: Person, howManyYearsPast: Int) = { 
    object incAge extends ->((age: Int) => age + howManyYearsPast) 
    everywhere(incAge)(person) 
} 

Ich bin mir ziemlich sicher, dass man diese ein in Erwägung ziehen könnte ":

Auf der anderen Seite, können Sie die inlined Version durch Entfernen des erwarteten Typs (aka Rückgabetyp) aus der Funktion kompilieren machen bug ", aber Inferenz ist nicht spezifiziert, so dass es eine Weile dauern wird, um herauszufinden, was genau sollte passieren.

+0

Also, das behebt den Typfehler, aber ich bin immer noch neugierig, wie ein Typ genau für den Typ, der abgeleitet werden soll, Typinterferenzen so stark brechen kann ... aber andererseits ist es scala, also sollte ich wahrscheinlich nicht trauen zu fragen, p – lunaryorn