7
votes

À Haskell, Concat construit une liste paresseusement mais ma propre version avec une torsion, ne pas

J'essaie de faire une fonction relativement simple qui est presque concessue mais avec une petite torsion. C'est censé être binaire ou ensemble les derniers et premiers éléments de chaque liste et les combiner dans le processus. Je travaille à apprendre à écrire du code capable de tirer parti des capacités de fusion de flux dans data.list.stream

J'ai vérifié que la concession de base fait ce qui est nécessaire et construit la liste paresseusement, cependant, cette version que j'ai créée. ne le fait pas. Dans la base, Concat est spécifié comme suit: xxx

voici mon code: xxx

La question que j'ai est, Comment puis-je écrire cela pour que la liste soit construite paresseuse? J'ai même essayé d'écrire Bappend en mimage de la définition (++) à la base, mais cela n'a pas fait de différence.

Pour le moment, j'utilise le code suivant, cela fonctionne comme je le souhaite, mais la performance tombe derrière Concat. En outre, il utilise une récursion explicite que j'aimerais éviter. xxx

Donc, la question que j'ai est, comment puis-je écrire ce code afin qu'il construit la liste paresseusement et sans récursion explicite?

Merci pour votre temps.

EDIT:

Mon intérêt principal, pour le moment, faire Code propre, concis et ossature avec les combinaisons standard. Je suis toujours très débutant avec la pensée fonctionnelle et j'aimerais voir une façon raisonnablement efficace de les mettre à utiliser ici.


4 commentaires

Je devinerais que le problème est que vous devez évaluer toute la première liste avant de pouvoir être capable de le faire. IMHO Il n'y a pas d'évaluation paresseuse possible.


Il y a définitivement un moyen de faire construire la liste résultante paresseusement. Concat réussit à cela et cela fait presque la même chose. En outre, le dernier extrait que j'ai posté est le faire comme je le veux. Cela n'a tout simplement pas atteint le niveau de performance de Concat.


Je vois la différence, la première version ou 'enfin (en dernier) avec le re


Je vois la différence, considérez BCONCAT sur [[1], [2], [4], [8,0]] qui est [15]. Le pliard1 calcule (1.. La tête [14]) par premier calcul [14] = repli1 [[2], [4], [8]] et ainsi de suite. La deuxième version calcule Bappend [[3], [4], [8]] alors Bappend [[7], [8]].


3 Réponses :


2
votes

Vous semblez avoir une faute de frappe, 'Bapennd' devrait être "Bappend" dans le premier extrait. Et je pense que "combiner" dans le dernier extrait devrait être "Bconcat".

On dirait que le premier (rabair1 Bappend) sera assez paresseux. Pourriez-vous élaborer sur le manque de paresse? P>

comme pour avoir besoin de "Derniers xs" et de "Derniers Xs" en même temps, vous pouvez souhaiter une seule traversée de XS: P>

let un [] = error "no last element"
    un (x:[]) = ([],x)
    un (x:xs) = let (ys,z) = un xs
                in (x:ys,z)


2 commentaires

Merci, j'ai corrigé les tybes. Manque de paresse comme en mangeant toute la mémoire dans mon système, causée par avoir à rendre la chaîne entière en mémoire avant que tout autre code ne puisse rien faire avec elle. Toute l'idée est de faire fonctionner ce programme en mémoire constante.


J'ai essayé d'utiliser votre fonction ONU pour avoir la tête et la queue en même temps, mais cela a fini par ralentir le code. Je soupçonne que cela a quelque chose à voir avec l'optimisation des flux de fusion que j'utilise. Ce "dernier XS" détenant la référence explique pourquoi je reçois une légère amélioration de la performance pour rendre le premier paramètre au bappend que j'utilise actuellement, strict.



4
votes

Votre définition semble stricte pour moi. Par exemple, essayez d'évaluer

 bconcat [] = error "bconcat: empty outer list"
 bconcat (xs:xss) = loop xss xs
   where loop [] ys = ys
         loop ((x:xs):xss) [y] = let z = x .|. y in seq z $ z : loop xss xs
         loop ([]:_) _ = error "bconcat: empty inner list"
         loop xss (y:ys) = y : loop xss ys


4 commentaires

Je ne suis pas sûr de la sorte de mes définitions de bconcat que vous vouliez essayer de "longueur $ bconcat [[[1,2,3], [4, non définie, 6]]" avec mais cela revient 5 dans les deux cas, comme je m'attendais.


Merci pour la version fusionnée de Bconcat. Ce code vole vraiment. C'est encore plus rapide que le concat ordinaire. Le programme que j'essaie d'optimiser les courses 40% plus rapidement avec celui-ci.


ACK, qui est cassé: "BCONCAT [[[1], [2], [4]]" donne "[3 *** exception: /tmp/foo.hs:(5,9)-(8,41): Motifs non exhaustifs en boucle de fonction "


Oui, je l'ai résolu pour mon propre code en ajoutant un cas particulier pour le moment où la nouvelle liste n'a qu'un élément. Il ressemble à ceci: boucle (x: []): XSS) [Y] = let z = x. |. y dans seq z $ boucle xss [z]



2
votes

Je peux changer la réponse en augmente plus près du problème d'origine en écrivant: xxx

Le ci-dessus ignore toutes les listes internes vides.


1 commentaires

Merci, mon code actuel n'a pas besoin de gérer des listes internes vides mais cela pourrait être utile à un autre but.