10
votes

Comment puis-je écrire de l'inverse par la plume efficace dans HASKELLL?

Notez que la solution triviale xxx

n'est pas très efficace, en raison de la croissance quadratique de la complexité. Si vous avez essayé d'utiliser la pliose habituelle pour replier la conversion (aveuglément), mais ma tentative xxx

n'a pas fonctionné comme on m'y attendait.


0 commentaires

5 Réponses :


22
votes

Essayez ceci:

reverse = foldl' (flip (:)) []


3 commentaires

Chris: Disons simplement: l'accumulateur a de type [A] -> [a]. Il s'agit essentiellement de créer beaucoup de lambdas encapsulés, qui ajoutent les éléments de la liste à l'avant de ce qui est passé - [].


@Chris je le préfère personnellement dans la notation ponctuelle, il est plus lisible (pour moi) de cette façon: inverse xs = pli-pli f id xs [] où f x r = r. (x:) . Ainsi, lorsque le résultat de pliose f id xs est enfin appliqué sur [] , le f x1 r1 est appelé, qui produit r1 . (x1 :) $ [] à quel point r1 est forcé. À la fin de la chaîne entière ID. (Xn :). .... (x2 :) (x1:) est appliqué à [] . Cela utilise la méthode standard HASKELL de codage de la différence ouverte (AKA "DIFFERENCE -" ) comme chaînes de fonctions de production de liste, :: [a] -> [a] . Idem est utilisé dans data.S. / code> je crois.


C'est l'un de ces cas rares où replier ' est pas mieux. L'action d'appliquer aveuglément un constructeur paresseux n'est jamais retardée car il n'y a jamais d'avantage à le faire. Dans le cas où le code produit est réellement différent, il ne peut s'agir que de pire.



9
votes

Considérez les éléments suivants:

reverse' xs = (appEndo . foldr (flip mappend . Endo . (:)) mempty $ xs) []
reverse' xs = (foldr (flip (.) . (:)) id $ xs) []
reverse' = flip (foldr (flip (.) . (:)) id) []


0 commentaires

1
votes
foldl (\acc x -> x:acc) [] [1,2,3]

2 commentaires

Mauvais endroit pour répondre, mais ce que je cherchais.


Je tiens à dire que je me suis rendu compte que ma réponse n'était pas correcte il y a très longtemps, mais à mon étonnement, de nombreuses personnes ont déjà voté (au total, j'ai eu 5 voix contre 5 votes). Je pense parfois que les gens atterrissent à cette page lorsque vous recherchez exactement cette réponse, j'ai donc décidé de le garder ici car à la fin, il s'agit d'aider les autres à trouver des réponses qu'ils recherchent.



4
votes

Fondamentalement, vous devez transformer 1: 2: 3: [] dans (3 :) (2 :) (1 :) et l'appliquer à []. Ainsi:

reverse' xs = foldr (\x g -> g.(x:)) id xs []


0 commentaires

-2
votes

Une ancienne question, je sais, mais existe-t-il quelque chose de non-optimal sur cette approche, il semble que la pliose serait plus rapide en raison de l'évaluation paresseuse et du code est assez concis:

 reverse' :: [a] -> [a]
 reverse' = foldr (\x acc -> acc ++ [x]) []


3 commentaires

Cette mise en œuvre est O (n ^ 2) sur la longueur de la liste. À chaque étape, le courant ACC devient des ordures et une nouvelle liste est créée avec x comme dernier élément. L'évaluation paresseuse ne change que quand cela se produit. Dans une langue stricte, cela se produirait avant inverse ' retour. Dans HASKELL, il se produira lorsque vous forcez la liste des résultats.


Ah, ça fait un sens parfait. N'a pas réfléchi au fait que cela créerait une nouvelle liste à chaque itération. Merci!


Certaines applications ++ STATICITIMENT-DISPONIBLES peuvent apparaître dans le lavage, mais ici ils se produiront tous et vous paierez beaucoup pour eux.