2017-03-17 1 views
2

Essayant de mapper un HList d'une classe polymorphique personnalisée, je reçois l'erreur redoutée "Impossible de trouver la valeur implicite pour le mappeur de paramètre" erreur. Un exemple de code:Mappage Shapeless et polymorphisme de sous-type avec le type personnalisé lié

import shapeless._ 

trait SubTrait 
case class A() extends SubTrait 
case class B() extends SubTrait 

case class C[T <: SubTrait](x: T) 

object TheMapper extends Poly1 { 
    implicit def default[T <: SubTrait, L[T] <: C[T]] = at[L[T]](_.x) 
} 

val ab = C(A()) :: C(B()) :: HNil 

println(ab.map(TheMapper)) 

Ceci fonctionne bien si la limite pour L [T] est par ex. Iterable (voir this very similar question, solution et commentaires). Qu'est-ce que je rate?

Répondre

5

Pour une raison quelconque, la vraie erreur est avalée. Si vous compilez cette étape par étape dans le REPL vous obtiendrez cette erreur:

error: type arguments [T] do not conform to class C's type parameter bounds [T <: SubTrait] 
     implicit def default[T <: SubTrait, L[T] <: C[T]] = at[L[T]](_.x) 
                ^

Le problème est que le T dans L[T] <: C[T] n'est pas le même que celui de T <: SubTrait. Il devient plus lisible si vous le renommer:

scala> object TheMapper extends Poly1 { 
    | implicit def default[T <: SubTrait, L[x] <: C[x]] = at[L[T]](_.x) 
    | } 
<console>:18: error: type arguments [x] do not conform to class C's type parameter bounds [T <: SubTrait] 
     implicit def default[T <: SubTrait, L[x] <: C[x]] = at[L[T]](_.x) 
                ^

La solution est de mettre une limite sur x.

scala> object TheMapper extends Poly1 { 
    | implicit def default[T <: SubTrait, L[x <: SubTrait] <: C[x]] = at[L[T]](_.x) 
    | } 
defined object TheMapper 

scala> val ab = C(A()) :: C(B()) :: HNil 
ab: shapeless.::[C[A],shapeless.::[C[B],shapeless.HNil]] = C(A()) :: C(B()) :: HNil 

scala> println(ab.map(TheMapper)) 
A() :: B() :: HNil 
+0

Notez que la convention consiste à écrire des variables de type local en minuscules. – OlivierBlanvillain

+0

@OlivierBlanvillain Oh, d'accord. Je ne peux pas dire que j'ai vu cela assez bien pour supposer que c'est la convention. Merci de l'avoir signalé. –

+0

En utilisant le REPL comme un débogueur, sympa :) Merci! –