[Haskell-fr] (no subject)

Nicolas Pouillard nicolas.pouillard at gmail.com
Sun Aug 21 20:01:07 CEST 2011


2011/8/21 Marc Chantreux <khatar at phear.org>:
> On Sun, Aug 21, 2011 at 03:42:33PM +0200, Marc Chantreux wrote:
>> main = readFile "/etc/passwd" >>= mapM_ print . lines
>
> hello,
Salut,

> je suis désolé pour les autres messages (modification un peu hative de
> la conf. de mon mailer).
>
> La question était en fait: comment produire une liste paresseuse des
> lignes d'un fichier. J'aimmerais pouvoir décrire une fonction
>
> cat  :: filePath -> [String]

Si la fonction «cat» a ce type alors elle ne peut faire aucun effet de bord.
Sa seule donnée en entrée est le nom d'un fichier et comme on le sait
on ne peut généralement pas déduire le contenu exacte d'un fichier
étant donné son nom :)

Tu cherches donc une fonction avec IO dans le type ou une variante permettant
d'acceder au système de fichier.

Un bon candidat semble être readFile (ou ses cousins getContents et
hGetContents).
La documentation mentione le fait que cette fonction lit
paraisseusement le fichier,
ce qui étant donné sont type est un peut étrange...

readFile :: FilePath -> IO String

En effet sont type nous dit que une fois le nom de fichier donné,
readFile "/etc/passwd"
est un "effet" qui va lire le fichier et "/etc/passwd" et renvoyé sont
contenu. Il n'y a donc
normalement qu'un seul effet. Enfin bon bref readFile triche un peut
mais c'est normalement
pas perceptible (malheureusement ça l'est), et l'on appelle cette
technique le "Lazy IO".

Donc si readFile est un bon candidat il nous reste à découper le
contenue en une liste de
lignes avec lines:

lines :: String -> [String]

cat :: FilePath -> IO [String]
cat fp = do xs <- readFile fp
                   return (lines fp)

ou en plus court:

cat :: FilePath -> IO [String]
cat = fmap lines . readFile

(fmap, (<$>), et liftM font la même chose.)

Au final, un petit =<< et le tour est joué:

mapM_ putStrLn . filter (isInfixOf "root") =<< cat "/etc/passwd"

(Un autre remarque au passage isInfixOf est fait pour être utilisé en infix :
  "root" `isInfixOf` line)

ou directement:

mapM_ putStrLn . filter ("root" `isInfixOf`) . lines =<< readFile "/etc/passwd"

ou aussi

putStr . unlines . filter ("root" `isInfixOf`) . lines =<< readFile
"/etc/passwd"

Amuse toi bien!

-- 
Nicolas Pouillard
http://nicolaspouillard.fr



More information about the Haskell-fr mailing list