Je suis vraiment intéressé à découvrir où se trouvent les différences, et plus généralement, à identifier les cas d'utilisation canoniques où les HLists ne peuvent pas être utilisées (ou plutôt, ne donnent aucun avantage par rapport aux listes régulières).
(Je suis conscient qu'il y en a 22 (je crois) TupleN
dans Scala, alors qu'on n'a besoin que d'une seule HList, mais ce n'est pas le genre de différence conceptuelle qui m'intéresse.)
J'ai marqué quelques questions dans le texte ci-dessous. Il n'est peut-être pas nécessaire d'y répondre, ils visent davantage à signaler des choses qui ne me sont pas claires et à orienter la discussion dans certaines directions.
Motivation
J'ai récemment vu quelques réponses sur SO où les gens ont suggéré d'utiliser les HLists (par exemple, comme fourni par Shapeless ), y compris une réponse supprimée à cette question . Elle a donné lieu à cette discussion , qui à son tour a suscité cette question.
Intro
Il me semble que les hlists ne sont utiles que lorsque vous connaissez le nombre d'éléments et leurs types précis de manière statique. Le nombre n'est en fait pas crucial, mais il semble peu probable que vous ayez jamais besoin de générer une liste avec des éléments de types différents mais statiquement connus avec précision, mais que vous ne connaissiez pas statiquement leur nombre. Question 1: Pourriez-vous même écrire un tel exemple, par exemple, en boucle? Mon intuition est qu'avoir une hlist statiquement précise avec un nombre statiquement inconnu d'éléments arbitraires (arbitraires par rapport à une hiérarchie de classes donnée) n'est tout simplement pas compatible.
HLists et tuples
Si cela est vrai, c'est-à-dire que vous connaissez statiquement le nombre et le type - Question 2: pourquoi ne pas simplement utiliser un n-uplet? Bien sûr, vous pouvez taper et replier en toute sécurité une HList (ce que vous pouvez également, mais pas en toute sécurité, faire sur un tuple à l'aide de productIterator
), mais comme le nombre et le type des éléments sont statiquement connus, vous pouvez probablement accéder aux éléments du tuple. directement et effectuez les opérations.
En revanche, si la fonction que f
vous mappez sur une hlist est si générique qu'elle accepte tous les éléments - Question 3: pourquoi ne pas l'utiliser via productIterator.map
? Ok, une différence intéressante pourrait venir de la surcharge de méthode: si nous avions plusieurs surchargés f
, avoir les informations de type les plus fortes fournies par la hlist (contrairement à productIterator) pourrait permettre au compilateur de choisir un fichier plus spécifique f
. Cependant, je ne sais pas si cela fonctionnerait réellement dans Scala, car les méthodes et les fonctions ne sont pas les mêmes.
HLists et entrée utilisateur
En partant de la même hypothèse, à savoir que vous devez connaître statiquement le nombre et les types d'éléments - Question 4: les hlists peuvent-elles être utilisées dans des situations où les éléments dépendent de tout type d'interaction utilisateur? Par exemple, imaginez remplir une hlist avec des éléments à l'intérieur d'une boucle; les éléments sont lus à partir de quelque part (interface utilisateur, fichier de configuration, interaction des acteurs, réseau) jusqu'à ce qu'une certaine condition se vérifie. Quel serait le type de la hlist? Similaire pour une spécification d'interface getElements: HList [...] qui devrait fonctionner avec des listes de longueur statiquement inconnue, et qui permet au composant A dans un système d'obtenir une telle liste d'éléments arbitraires du composant B.
FunctionN
traits ne savent pas comment faire l'abstraction sur l'arité: github.com/paulbutcher/ScalaMock/blob/develop/core/src/main / ... github.com/paulbutcher/ScalaMock/blob / develop / core / src / main /… Malheureusement, je ne connais aucun moyen d'utiliser Shapeless pour éviter cela, étant donné que je dois faire face à de «vrais»FunctionN
sPour être clair, une HList n'est essentiellement rien de plus qu'une pile de
Tuple2
sucre légèrement différent sur le dessus.Donc, votre question porte essentiellement sur les différences entre l'utilisation de tuples imbriqués et de tuples plats, mais les deux sont isomorphes donc à la fin il n'y a vraiment aucune différence, sauf la commodité dans laquelle les fonctions de bibliothèque peuvent être utilisées et la notation qui peut être utilisée.
la source
Il y a beaucoup de choses que vous ne pouvez pas (bien) faire avec les tuples:
Vous pouvez faire tout cela avec des tuples bien sûr, mais pas dans le cas général. Ainsi, l'utilisation de HLists rend votre code plus SEC.
la source
Je peux expliquer cela dans un langage très simple:
La dénomination tuple vs liste n'est pas significative. Les HLists peuvent être nommées HTuples. La différence est que dans Scala + Haskell, vous pouvez le faire avec un tuple (en utilisant la syntaxe Scala):
pour prendre un tuple d'entrée d'exactement deux éléments de n'importe quel type, ajouter un troisième élément et renvoyer un tuple entièrement typé avec exactement trois éléments. Mais bien que ce soit complètement générique sur les types, il doit spécifier explicitement les longueurs d'entrée / sortie.
Ce qu'une HList de style Haskell vous permet de faire est de rendre ce générique sur toute la longueur, de sorte que vous pouvez ajouter à n'importe quelle longueur de tuple / liste et récupérer un tuple / liste entièrement statiquement typé. Cet avantage s'applique également aux collections de typage homogène où vous pouvez ajouter un int à une liste d'exactement n entiers et récupérer une liste typée statiquement pour avoir exactement (n + 1) entiers sans spécifier explicitement n.
la source