2012-11-25 2 views
0

J'ai commencé à apprendre Haskell il y a quelques jours et j'ai rencontré quelques problèmes. Le premier problème concerne l'impression d'une liste de nombres. Le comportement souhaité est le suivant:Haskell Imprimer une liste avec un formatage

entrée

: [1,2,3,4,5,6]

sortie: 1 2 3 | 4 5 6

Donc, c'est un concept simple, j'ai juste besoin de sortir les éléments d'une liste avec le "|" symbole inséré entre tous les trois chiffres, mais je ne peux pas pour la vie de moi le comprendre. Il semble que la plupart des choses que j'ai essayées impliquent des chaînes et même si j'étais capable d'obtenir la liste à des chaînes telles que ["1", "2", "3", ...] toutes les méthodes que j'ai essayé d'imprimer les numéros chacun sur leur propre ligne, ce qui n'est pas ce dont j'ai besoin.

Toute aide serait grandement appréciée.

Répondre

5

Utilisation du package split (récemment ajouté à la plate-forme Haskell):

> import Data.List   -- for intercalate 
> import Data.List.Split -- for chunksOf 
> intercalate " | " . map unwords . chunksOf 3 $ map show [1..7] 
"1 2 3 | 4 5 6 | 7" 

La documentation pertinente: chunksOf, unwords, intercalate.

+0

Wow! Merci, juste ce dont j'avais besoin – Ockham

+0

Je reçois 'Impossible de trouver le module' Data.List.Split''. –

2

Vous pouvez faire

threes [] = "" 
threes xs = let (front,rest) = splitAt 3 xs in 
    unwords (map show front) ++ 
     if null rest then "" else " | " ++ threes rest 

donnant

*Main> threes [1..10] 
"1 2 3 | 4 5 6 | 7 8 9 | 10" 

Fonctions: j'ai utilisé

splitAt :: Int -> [a] -> ([a], [a]) 
    -- splitAt 2 "Hello Mum" = ("He","llo Mum") 

unwords :: [String] -> String 
    -- unwords ["Hello","there","everyone"] 
    --  = "Hello there everyone" 

null :: [a] -> Bool 
null [] = True 
null _ = False 
3

est ici une façon.

import Data.List (cycle) 

format :: Show a => [a] -> String 
format = concat . zipWith (++) ("" : cycle [" ", " ", " | "]) . map show 

Cela ne présente l'inconvénient que le regroupement en groupes de trois est codé en dur, mais il est pas trop difficile de généraliser.

1

La première partie est la plus facile, vous devez convertir les nombres à String s,

format :: (Num a, Show a) => [a] -> String 
format xs = result 
    where 
    strings = map show xs 

fait cela. Ensuite, nous devons diviser une liste en éléments de trois éléments (plus généraux, n). splitAt divise une liste en une partie avant du nombre souhaité d'éléments - si la liste est suffisamment longue - et un reste. Itérer la procédure sur le reste, alors que ce n'est pas vide conduit au résultat souhaité.

chunk :: Int -> [a] -> [[a]] 
chunk _ [] = [] 
chunk n xs = ys : chunk n zs 
    where 
    (ys, zs) = splitAt n xs 

C'est un motif récurrent, donc il y a un combinateur pour cela, et nous aurions pu écrire

import Data.List (unfoldr) 

chunk :: Int -> [a] -> [[a]] 
chunk n = unfoldr split 
    where 
    split [] = Nothing 
    split xs = Just $ splitAt n xs 

Nous pouvons continuer notre format,

format :: (Num a, Show a) => [a] -> String 
format xs = result 
    where 
    strings = map show xs 
    chunks = chunk 3 strings 

Ensuite, nous avons besoin pour insérer un "|" entre tous les morceaux, cela est fait par intercalate de Data.List, et enfin, concaténer toutes les chaînes avec des espaces entre eux, tha t est ce que unwords fait, et donc

format :: (Num a, Show a) => [a] -> String 
format xs = result 
    where 
    strings = map show xs 
    chunks = chunk 3 strings 
    result = unwords $ intercalate "|" chunks 

Ou

format = unwords . intercalate "|" . chunk 3 . map show 
Questions connexes