IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Haskell Discussion :

Élimination d'un bloc "do" par chainage


Sujet :

Haskell

  1. #1
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut Élimination d'un bloc "do" par chainage
    Salut, c'est encore moi

    Je n'aime pas beaucoup les blocs do, et m'efforce donc de les supprimer.
    Sur le coup, j'ai un peu de mal.

    Le code avec le do:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import qualified Data.ByteString.Lazy as L
     
    hasElfMagic :: L.ByteString -> Bool
    hasElfMagic content = L.take 4 content == elfMagic
        where elfMagic = L.pack [0x7f, 0x45, 0x4c, 0x46]
     
    isElfFile :: FilePath -> IO Bool
    isElfFile path = do
      content <- L.readFile path
      return (hasElfMagic content)
    Je souhaite donc supprimer le do dans l'action isElfFile.

    Ma première idée a été d'utiliser l'opérateur >>=, puis j'ai essayé de chainer les fonctions avec des . (points)
    Rien n'y fait, Haskell ne me laissera pas mélanger des actions et des fonctions :
    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
    Prelude> :load isElf
    [1 of 1] Compiling Main             ( isElf.hs, interpreted )
     
    isElf.hs:8:37:
        Couldn't match expected type `IO Bool' against inferred type `Bool'
        In the second argument of `(>>=)', namely `hasElfMagic'
        In the expression: L.readFile path >>= hasElfMagic
        In the definition of `isElfFile':
            isElfFile path = L.readFile path >>= hasElfMagic
    Failed, modules loaded: none.
    Prelude> :load isElf
    [1 of 1] Compiling Main             ( isElf.hs, interpreted )
     
    isElf.hs:8:26:
        Couldn't match expected type `L.ByteString'
               against inferred type `IO L.ByteString'
        In the second argument of `(.)', namely `L.readFile'
        In the expression: hasElfMagic . L.readFile
        In the definition of `isElfFile':
            isElfFile = hasElfMagic . L.readFile
    Failed, modules loaded: none.
    J'ai fini par trouver une solution avec une fonction lambda, mais je trouve que c'est beaucoup de bazar pour une petite chose
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    isElfFile path = L.readFile path >>= (\contents -> return $ hasElfMagic contents)
    Existe-t-il une solution plus concise ?

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Citation Envoyé par Antoine_935 Voir le message
    Existe-t-il une solution plus concise ?
    Ceci est plus concis, mais pas forcément plus lisible:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    isElfFile path = L.readFile path >>= return . hasElfMagic
    La transformation que tu fais est souvent indentée comme ceci, en écho au bloc do (et ça reste lisible si le bloc est plus long):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    isElfFile path =
            L.readFile path >>= \contents ->
            return $ hasElfMagic contents

  3. #3
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Citation Envoyé par dividee Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    isElfFile path = L.readFile path >>= return . hasElfMagic
    Gnarf, j'y étais presque

    Je n'avais pas percuté que return était une fonction.
    En inversant l'opérateur >>=, on peut arriver à une notation presque point-free.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    isElfFile :: FilePath -> IO Bool
    isElfFile path = return . hasElfMagic =<< L.readFile path
    Seulement, dès que je retire le path, c'est la catastrophe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    *Main System.FilePath> :load isElf
    [1 of 1] Compiling Main             ( isElf.hs, interpreted )
     
    isElf.hs:8:12:
        Couldn't match expected type `IO Bool' against inferred type `Bool'
          Expected type: FilePath -> IO Bool
          Inferred type: FilePath -> Bool
        In the first argument of `(=<<)', namely `return . hasElfMagic'
        In the expression: return . hasElfMagic =<< L.readFile
    Failed, modules loaded: none.
    Une idée ?


    Merci en tout cas pour cette belle réponse


    Autre question en passant :
    L'opérateur >> existe pour ordonner deux actions.
    Existe-t-il l'opérateur inverse << ?*(celui là ne semble pas exister du moins...)

  4. #4
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Citation Envoyé par Antoine_935 Voir le message
    Une idée ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    isElfFile = (=<<) (return . hasElfMagic) . L.readFile
    -- ou bien
    isElfFile = (return . hasElfMagic =<<) . L.readFile
    -- ou encore
    isElfFile = (>>= return . hasElfMagic) . L.readFile
    Mais si tu préfères ça au bloc do, il faut te faire soigner

    [EDIT:] pour ton autre question, tu peux toujours écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    (<<) :: Monad m => m b -> m a -> m b
    (<<) = flip (>>)

  5. #5
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Citation Envoyé par dividee Voir le message
    Mais si tu préfères ça au bloc do, il faut te faire soigner
    Haha, probablement

    Merci pour ces réponses bien claires

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 38
    Points : 37
    Points
    37
    Par défaut
    Citation Envoyé par Antoine_935 Voir le message
    Haha, probablement

    Merci pour ces réponses bien claires
    ce qui est de la forme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    do variable <- action
       return ( fonction variable )
    peut généralement se transformer en

    Donc là on a :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    is2 p = hasElfMagic `fmap` L.readFile p
    Et en pointfree:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    is3 = (hasElfMagic `fmap`) . L.readFile

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

Discussions similaires

  1. [ICEFACES] Les quotes sont remplacées par &#_39;
    Par Mathieu.J dans le forum JSF
    Réponses: 0
    Dernier message: 19/01/2010, 16h09

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