2016-06-30 14 views
2

Angenommen, ich habe Container-Markermerkwürdiger Einfluss von impliziten Mapper auf impliziten mapped Parameter

case class TypedString[T](value: String) 

und Teilfunktion Trick

abstract class PartFunc[Actual <: HList] { 
    val poly: Poly 

    def apply[L1 <: HList](l: L1)(implicit 
            mapped: Mapped.Aux[Actual, TypedString, L1], 
            mapper: Mapper[poly.type, L1]): L1 = l 
} 

Poly für Mapper

object f extends (TypedString ~>> String) { 
    def apply[T](s : TypedString[T]) = s.value 
} 

und Ergebnis Methode

def func[Actual <: HList] = new PartFunc[Actual] { 
    val poly = f 
} 

Anwendungsbeispiel:

func[ 
    Int :: String :: HNil 
](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil) 

Dieser Code nicht bei der Kompilierung, weil Compiler nicht Mapped implizite Parameter finden:

could not find implicit value for parameter mapped: 
    shapeless.ops.hlist.Mapped[shapeless.::[Int,shapeless.::[String,shapeless.HNil]],nottogether.MapperTest.TypedString]{type Out = shapeless.::[nottogether.MapperTest.TypedString[Int],shapeless.::[nottogether.MapperTest.TypedString[String],shapeless.HNil]]} 
     ](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil) 

Aber wenn wir Mapper implizite Parameter von PartFunc.apply(...) Signatur entfernen alles funktioniert gut. Also ich habe keine Ahnung warum und wie auf Mapped beeinflussen.

Antwort

3

Der Compiler beschwert sich über Mapped, während das eigentliche Problem mit ist. Ich bin mir nicht sicher, warum, aber es scheint etwas falsch zu gehen mit einem Mapped für den Singleton-Typ poly.type, wenn poly ist ein abstrakter Wert oder ein Konstruktor-Argument von PartFunc.

wäre eine Lösung poly ein P <: Poly und vorbei am Singleton mit Actual geben zusammen zu machen, wenn wir das schaffen PartFunc:

import shapeless._ 
import ops.hlist.{Mapped, Mapper} 
import poly.~>> 

abstract class PartFunc[Actual <: HList, P <: Poly] { 
    val poly: P 
    def apply[L1 <: HList](l: L1)(implicit 
    mapped: Mapped.Aux[Actual, TypedString, L1], 
    mapper: Mapper[P, L1] 
): mapper.Out = mapper(l) 
} 

def func[Actual <: HList] = new PartFunc[Actual, f.type] { val poly = f } 

Oder mit einer regulären Klasse:

class PartFunc[Actual <: HList, P <: Poly](poly: P) { 
    def apply[L1 <: HList](l: L1)(implicit 
    mapped: Mapped.Aux[Actual, TypedString, L1], 
    mapper: Mapper[P, L1] 
): mapper.Out = mapper(l) 
} 

def func[Actual <: HList] = new PartFunc[Actual, f.type](f) 

Beachten Sie, dass wir jetzt muss mapper(l) schreiben, denn l map poly wird immer noch nach einem Mapped[poly.type, L1] suchen.

Wir können func jetzt anrufen:

func[ 
    Int :: String :: HNil 
](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil) 
// String :: String :: HNil = 42 :: hello :: HNil 

Ich bin sicher, dass jemand mit etwas mehr in die Tiefe Kenntnis des Systems Scala Typ uns eine deutlichere Erklärung liefern könnte und möglicherweise eine bessere Lösung für dieses Problem.

+0

Ich habe diese Frage im formlosen Gitterzimmer ohne Antwort gestellt. Danke für Ihre Unterstützung. Welches Buch oder welche Artikel empfehlen Sie zu lesen, um mit den Scala-Typen vertrauter zu sein? –

Verwandte Themen