Quelle est la bonne façon d'implémenter des appels récursifs dans une méthode typeclass sans forme?Shapeless: appels récursifs dans la classe de type
(Une première mise en garde:.! J'apprends informes, donc il peut y avoir des réponses évidentes/alternatives Je ne sais pas encore Toute aide est grandement appréciée)
J'ai une classe de types qui convertit une classe de cas en une structure imbriquée d'autres objets - similaire à et inspirée par l'exemple ToMapRec
mentionné dans this stackoverflow question - sauf qu'au lieu de renvoyer une Map potentiellement récursive, elle renvoie une classe de cas composée de membres potentiellement récursifs. Ainsi, au lieu de convertir une instance de MyType
:
trait GetsConverted
case class MyType(someData: String, one: GetsConverted, other: GetsConverted) extends GetsConverted
case class MyOtherType(blah: AndSoOn) extends GetsConverted
case class AndSoOn(eventualFinalValue: Int)
dans un éventuellement récursive/imbriquée Map[String,Any]
(comme dans l'autre question), il retourne quelque chose comme une instance de:
case class ReturnType(name: String, data: Option[Any], more: Set[ReturnType])
Pour créer le more
Le membre semble avoir besoin de faire un appel récursif à l'intérieur de la classe de type. Mais l'appel de la méthode de conversion de la classe type à l'intérieur d'une autre méthode nécessite l'insertion dans les paramètres implicites de tous les types de cette fonction de l'appel le plus externe. Ainsi, au lieu d'une conversion de classe de types comme:
implicit def hconsToMapRec0[K, V, A <: HList, B <: HList](implicit
wit: Witness.Aux[K],
gen: LabelledGeneric.Aux[V, R],
tmrH: Lazy[ToMapRec[A]],
tmrT: Lazy[ToMapRec[B]]
): ReturnType = ???
une méthode profondeur de trois (je suppose), il faudrait une signature de fonction quelque chose comme:
implicit def hconsToMapRec0[K, V, A <: HList, B <: HList, W, C <: HList, D <: HList, X, E <: HList, F <: HList](implicit
wit: Witness.Aux[K],
gen0: LabelledGeneric.Aux[V, A],
tmrH0: Lazy[ToMapRec[A]],
tmrT0: Lazy[ToMapRec[B]],
gen1: LabelledGeneric.Aux[W, C],
tmrH1: Lazy[ToMapRec[C]],
tmrT1: Lazy[ToMapRec[D]],
gen2: LabelledGeneric.Aux[X, E],
tmrH2: Lazy[ToMapRec[E]],
tmrT2: Lazy[ToMapRec[F]]
): ReturnType = ???
Ou peut-être pire. En général, cette approche nécessiterait une méthode dont les paramètres implicites sont multipliés par autant de niveaux de profondeur dans cette récursivité. Et le nombre de niveaux de profondeur n'est connu qu'à l'exécution. Donc, cela ne peut pas être le moyen de le faire. Cela ressemble aux méthodes 22-arity codées en dur dans la bibliothèque de collections scala. Puisque la raison d'être de Shapeless est de faire abstraction de l'arité, cela semble être un problème appelant à plus de Shapeless-foo que j'ai appris jusqu'à présent.
La question est donc: comment voulez-vous écrire un classe de types informes pour convertir une chose classe de cas arbitraire structuré comme l'exemple MyType
ci-dessus dans une valeur définie récursivement comme:
ReturnType("MyType", Some("someData"), Set(
ReturnType("MyOtherType", None, Set(
ReturnType("AndSoOn", Some(10), Set())
)),
ReturnType("MyOtherType", None, Set(
ReturnType("AndSoOn", Some(20), Set())
))
))
Merci pour cela! +1 pour l'effort, mais je n'ai probablement pas fait un bon travail de mise en évidence où la récursion est nécessaire dans la requête originale.C'est assez bien défini dans le même problème que nous avons tous les deux liés. Mais le problème survient lorsque le site d'appel se trouve dans une autre fonction (récursive). Faire ceci une fois est simple, mais comment appelleriez-vous récursivement: 'val returnType = tmpr (gen.to (m))'? – Ryan