Idiomatiques efficace Haskell ajouter?

Liste et les inconvénients de l'opérateur (:) sont très fréquents en Haskell. Le contre est notre ami. Mais parfois, j'ai envie d'ajouter à la fin d'une liste à la place.

xs `append` x = xs ++ [x]

Cela, malheureusement, est pas un moyen efficace de mettre en œuvre.

J'ai écrit jusqu' Le triangle de Pascal en Haskell, mais j'ai dû utiliser la ++ [x] anti-idiome:

ptri = [1] : mkptri ptri
mkptri (row:rows) = newRow : mkptri rows
    where newRow = zipWith (+) row (0:row) ++ [1]

à mon humble avis, c'est une belle lisible le triangle de Pascal et de tous, mais l'anti-idiome ne m'irrite. Quelqu'un peut m'expliquer (et, idéalement, m'indiquer un bon tutoriel) sur ce que l'idiomatiques structure de données est pour les cas où vous voulez ajouter à la fin de manière efficace? J'espère que pour la proximité de la-liste-comme la beauté dans cette structure de données et de ses méthodes. Ou, alternativement, expliquez-moi pourquoi cet anti-idiome est en fait pas si mauvais que ça pour ce cas (si vous croyez que tel est le cas).


[modifier] La réponse que j'aime le plus Data.Sequence, qui n'ont, en effet, "près de de la liste comme la beauté." Pas sûr de savoir comment je me sens sur la rigueur d'exploitation. D'autres suggestions et des idées différentes sont toujours les bienvenus.

import Data.Sequence ((|>), (<|), zipWith, singleton)
import Prelude hiding (zipWith)

ptri = singleton 1 : mkptri ptri

mkptri (seq:seqs) = newRow : mkptri seqs
    where newRow = zipWith (+) seq (0 <| seq) |> 1

Maintenant nous avons juste besoin de la Liste à être une classe, alors que d'autres structures peuvent utiliser ses méthodes comme zipWith sans le cacher de Prélude, ou en le qualifiant. 😛

  • La liste n'est pas une classe, mais ListLike est. Il y a un Données.Séquence instance est disponible aussi. hackage.haskell.org/package/ListLike-3.0.1
  • Aléatoire gêne: j'ai d'abord essayé d'écrire newRow = 1 <| zipWith (+) seq (drop 1 seq) |> 1, qui à mon humble avis est très beau pour exprimer le triangle de Pascal en montrant explicitement les 1 aux deux extrémités de chaque ligne. Malheureusement, j'ai eu cette erreur: cannot mix '<|' [infixr 5] and '|>' [infixl 5] in the same infix expression
  • Cette seconde newRow est très belle. J'ai eu un non-idéalement-succès avec ZipLists (je m'attendais à quelque chose de plus général, mais c'était trop compliqué), hpaste.org/44613/pascals_ziplist. Avec l'idiome crochets de la she préprocesseur, et quelques maison combinators il ressemble à ceci: pascalsNextLine old = 1 <& (| tail' old + init' old |) &> 1 Il serait intéressant de savoir si il ya quelque chose à généraliser cette idée de la vôtre.
  • Il semble que les deux |> et <| ont la même priorité, de sorte qu'ils ne peuvent pas passer à côté de l'autre. Je me demande si il existe un moyen de changer cela, sans se briser d'autres fichiers, sorta sur un fichier par fichier.
  • Je me demandais à propos de cette trop. Une idée que j'avais était d'utiliser un O(1) cons comme un ajout, mais de là à O(n) reverse la liste résultante. Voir aussi: le contraste entre la mise en œuvre de map par rapport à reverse.
InformationsquelleAutor Dan Burton | 2011-03-04