1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    juillet 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : juillet 2011
    Messages : 10
    Points : 8
    Points
    8

    Par défaut foldl à la place d'un paterm matching

    Bonjour,

    Jaime bien les folds parce que ça utilise les lambdas et la récursion terminale (je crois).
    J'aimerais savoir si on peut remplacer ma fonction filt' par un fold comme plus haut dans mon code (script simplissime que j'ai codé pour un script bash). Ou même reduire ce code(j'apprends donc je me preocuperais de la lisibilité une autre fois)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    rev' :: String -> String --fonction reverse...
    rev' = foldl (\acc x -> x : acc) []
    
    patio' :: String -> Integer --dis si la chaine contient un '/'
    patio' = foldl (\acc x -> if x == '/' then  1 + acc else acc) 0
    
    filt' :: String -> String -- vire le debut de la chaine jusqu'au premier '/'
    filt' [] = []
    filt' (x:xs) = if x == '/' then xs else filt' xs
    
    rparsePah :: String -> String --main
    rparsePah xs = if patio' xs /= 0 then rev' $ filt' $ rev' xs else xs
    
    main = do interact rparsePah
    En attendant une réponse, bonne journée.

  2. #2
    Candidat au Club
    Homme Profil pro
    Collégien
    Inscrit en
    août 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Collégien
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : août 2011
    Messages : 2
    Points : 3
    Points
    3

    Par défaut

    Si j'ai bien compris, voilà qui fera l'affaire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    filt' = reverse . snd . foldl (\acc x -> if fst acc then (True, x : snd acc) else if x == '/' then (True, []) else (False, [])) (False, [])

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    juillet 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : juillet 2011
    Messages : 10
    Points : 8
    Points
    8

    Par défaut

    Bonsoir,
    C'est bien ce que je cherchais à faire mais pour dire vrai je ne comprends pas tout à fait.

    Que vient faire le () dans :
    Merci d'avoir répondu.

  4. #4
    Candidat au Club
    Homme Profil pro
    Collégien
    Inscrit en
    août 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Collégien
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : août 2011
    Messages : 2
    Points : 3
    Points
    3

    Par défaut

    Citation Envoyé par Nel_Star Voir le message
    Bonsoir,
    C'est bien ce que je cherchais à faire mais pour dire vrai je ne comprends pas tout à fait.

    Que vient faire le () dans :
    Merci d'avoir répondu.
    Rien, c'était de la bêtise.

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    juillet 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : juillet 2011
    Messages : 10
    Points : 8
    Points
    8

    Par défaut

    Ça marche.
    J'ai mis résolu. Je te remercie ça faisait bien deux jours que je me cassais la tête.
    Tchao.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : octobre 2007
    Messages : 36
    Points : 54
    Points
    54

    Par défaut

    Attention, bien que très pratique, il ne faut pas utiliser les folds à tord et à travers
    Citation Envoyé par Nel_Star Voir le message
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    rev' :: String -> String --fonction reverse...
    rev' = foldl (\acc x -> x : acc) []
    Effectivement dans ce cas là, c'est une bonne utilisation du fold, également utilisé dans le prélude Haskell pour la fonction reverse (l'implémentation est visible en cliquant sur 'Sources')
    Citation Envoyé par Nel_Star Voir le message
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    patio' :: String -> Integer --dis si la chaine contient un '/'
    patio' = foldl (\acc x -> if x == '/' then  1 + acc else acc) 0
    Là par exemple, c'est une très mauvaise utilisation, le but est de faire une recherche d'élément, et toute la liste est parcourue pour trouver ta réponse, alors que la recherche pourrait être arrêté avant. Une manière plus directe de faire (et qui est également récursive terminale) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    chercheElement :: Char -> String -> Bool
    chercheElement _ [] = False
    chercheElement a (x:xs) | a == x = True
                            | otherwise = chercheElement a xs
    Il existe d'autre manière de faire, notamment comme l'implémentation de la fonction elem, mais elles mettent en oeuvre des fonctions d'ordre supérieure et (surtout), s'appuie sur l'évaluation paresseuse de Haskell (chose que ne permet pas le foldl dans ce cas là).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    filt' :: String -> String -- vire le debut de la chaine jusqu'au premier '/'
    filt' [] = []
    filt' (x:xs) = if x == '/' then xs else filt' xs
    Cette fonction ne bénéficierai pas d'être implémenté avec un fold, sachant qu'on veut se débarrasser du début de la liste, la dropper, on peut utiliser la fonction dropWhile
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    rparsePath :: String -> String
    rparsePath str
        | not $ '/' `elem` str = str
        | otherwise = reverse . dropUntilFirstSlash $ reverse str
               where dropUntilFirstSlash = reverse . safeTail . dropWhile (/= '/') . reverse
                     safeTail (x:xs) = xs
                     safeTail _ = []
    En bonus, la version simplifié du programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    import System.FilePath( dropFileName )
    main :: IO ()
    main = interact (safeTail . dropFileName)
               where safeTail (x:xs) = xs
                     safeTail _ = []
    Il ne faut pas hésiter à fouiner la librairie existante en Haskell il y a très souvent moyen de se simplifier la vie

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    juillet 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : juillet 2011
    Messages : 10
    Points : 8
    Points
    8

    Par défaut

    Bonsoir,
    Petite mise à jour. Aprés avoir lu vos conseils, j'ai legerement modifié mon script.
    Qui ressemble maintenant à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    import System.Environment
    
    nonPresent :: Char -> String -> Bool
    nonPresent a str = not $ elem a str
    
    rparsePath :: String -> String
    rparsePath str
        | nonPresent '/' str = str
        | otherwise = reverse . safeTail . dropWhile (/= '/') . reverse $ str
    
    rparseFile :: String -> String
    rparseFile str
        | nonPresent '/' str = str
        | otherwise = reverse . takeWhile (/= '/') . reverse $ str
    
    rparseExt :: String -> String
    rparseExt str
        | nonPresent '.' str = str
        | otherwise = reverse . takeWhile (/= '.') . reverse $ rparseFile str
    
    rparseName :: String -> String
    rparseName str
        | nonPresent '.' str = str
        | otherwise = reverse . safeTail . dropWhile (/= '.') . reverse $ rparseFile str
    
    safeTail :: String -> String
    safeTail (x:xs) = xs
    safeTail _ = []
    
    argFilt :: [String] -> String
    argFilt cmdLineArgs
        | first == "-p" = rparsePath secnd
        | first == "-ne" = rparseFile secnd
        | first == "-n" = rparseName secnd
        | first == "-e" = rparseExt secnd
        | first == "-pn" = rparsePath secnd ++ '/':rparseName secnd
        | otherwise = "bad option argument"
      where secnd = head $ tail cmdLineArgs
            first = head cmdLineArgs
    
    arg_verif :: [String] -> Bool
    arg_verif a = a /= [] && (length a) >= 2
    
    main :: IO ()
    main = do
            args <- getArgs
            putStrLn $ if arg_verif args then argFilt args else "nothing to process"
    Bon le code est plutot facile à lire mais en gros soit blob = /dummy/path/lol.test, le fait d'appeler le script avec l'option -p donnera /dummy/path, avec -n lol, -e test, -ne lol.test, -pn /dummy/path/lol.

    En fait j'avais à l'origine besoin d'interfacer(premier post) vim avec ghc,gcc, pdflatex. Et la variable % de vim demande un peu de tweak.

    Alors je sais qu'il existe des solution plus rapides(j'en connais quelque unes) avec sed, awk, python, etc... Mais je prefere utiliser des outils que je maitrise.

    Dernierement, utiliser System.FilePath m'a donné des erreurs de types à en avoir mal à la tête(j'ai fini par comprendre...) et donc je m'en passe ici.

    La encore vos comentaires sont les bienvenus. Salute.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : octobre 2007
    Messages : 36
    Points : 54
    Points
    54

    Par défaut

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    arg_verif :: [String] -> Bool
    arg_verif a = a /= [] && (length a) >= 2
    est strictement équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    arg_verif :: [String] -> Bool
    arg_verif a = length a >= 2
    vu que si une liste est vide, sa taille est 0. Et il est plus intéressant d'utiliser le pattern matching plutôt que head & tail lorsque cela est possible :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import System.Environment
    import System.FilePath
    
    safeTail :: String -> String
    safeTail (x:xs) = xs
    safeTail _ = []
    
    optionTodo :: [(String, FilePath -> FilePath)]
    optionTodo = [("-p", dropFileName)
                 ,("-n", dropExtension . takeFileName)
                 ,("-ne", takeFileName)
                 ,("-e", safeTail . takeExtension)
                 ,("-pn", \a -> dropExtension a ++ ".")
                 ]
    
    main :: IO ()
    main = do
        args <- getArgs
        case args of
            (opt: name: _) -> case opt `lookup` optionTodo of
                    Nothing -> putStrLn $ "Wrong argument " ++ opt
                    Just act -> putStrLn $ act name
            _ -> putStrLn "Wrong number of argument"
    En matchant sur args, on évite beaucoup de problème et de risques d'exception.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    juillet 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : juillet 2011
    Messages : 10
    Points : 8
    Points
    8

    Par défaut

    Bonjour,
    Merci Twinside. J'ai eu du mal à comprendre ce que voulait dire Nothing et Just. Du coup pas mal de choses dont je passais à coté.

    J'ai légérement modifié le script pour qu'il soit plus à mon gout :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import System.Environment
    import System.FilePath
    
    safeTail :: String -> String
    safeTail (x:xs) = xs
    safeTail _ = []
    
    optionTodo :: [(String, FilePath -> FilePath)]
    optionTodo = [("-p", reverse.safeTail.reverse.dropFileName)
                 ,("-n", dropExtension . takeFileName)
                 ,("-ne", takeFileName)
                 ,("-e", safeTail . takeExtension)
                 ,("-pn", dropExtension)
                 ]
    
    main :: IO ()
    main = do
        args <- getArgs
        case args of
            (opt: name: _) -> case opt `lookup` optionTodo of
                    Nothing -> putStrLn $ "Wrong argument " ++ opt
                    Just act -> putStrLn $ act name
            _ -> putStrLn "Wrong number of argument"
    Voila. Salutations.

    EDIT : En fait j'ai un probleme avec la ligne 22. A quoi sert act (je crois que ça initie l'action qui est donnée par optionTodo)?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 16/04/2015, 16h30
  2. Donne deux places match Rugby Pro D2
    Par Civodul4 dans le forum Petites annonces
    Réponses: 0
    Dernier message: 29/10/2009, 15h46
  3. [SAX] Vitesse contre place en mémoire
    Par Dinaïz dans le forum XML
    Réponses: 6
    Dernier message: 15/10/2004, 14h37
  4. Place des autodidactes sur le marché du travail
    Par Argh! dans le forum Emploi
    Réponses: 21
    Dernier message: 24/05/2003, 23h01
  5. template match="node() mais pas text()"
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 26/03/2003, 11h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo