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 :

unsafePerformIO et référence transparentielle


Sujet :

Haskell

  1. #1
    Nouveau Candidat au Club
    Inscrit en
    Novembre 2012
    Messages
    1
    Détails du profil
    Informations forums :
    Inscription : Novembre 2012
    Messages : 1
    Points : 1
    Points
    1
    Par défaut unsafePerformIO et référence transparentielle
    Salut à tous,
    j'apprends le Haskell par moi-même,
    je me heurte à des points que je ne comprends pas.
    Il est mentionné que la fonction unsafePerformIO est une fonction à éviter,
    dangereuse etc, si j'ai bien compris, elle peut retourner des résultats différents ce qui est contre la transparence référentielle.
    Sur la page http://cvs.haskell.org/Hugs/pages/li...IO-Unsafe.html
    Il est donné un bout de code qui est censé mettre en évidence ce fait,
    mais je n'arrive pas à voir en quoi ça prouve que quelque chose ne va pas, une explication ?
    Quelqu'un pourrait me fournir d'autres bouts de code que je peux tester et qui mettraient en évidence des comportements bizarres ?
    Merci d'avance.

  2. #2
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2009
    Messages : 97
    Points : 307
    Points
    307
    Par défaut
    Soit la fonction hasard suivante

    Quand elle sera exécutée, elle produira un nombre entier aléatoire.

    Soit maintenant la fonction foo suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    foo :: Int -> Int
    foo i = if even (unsafePerformIO hasard) then i + 2 else i + 1
    Dire qu'une fonction est pure ça veut dire que l'on peut partout la remplacer par sa valeure finale.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    fonctionPure :: Int -> Int
    fonctionPure x = x + 2
     
    exemple = (fonctionPure 1) + (fonctionPure 1) -- peut être remplacer directement par exemple = 3 + 3 sans aucun risque
    Pour tout x appartenant aux entiers, fonctionPure x == fonctionPure x

    Cette caractéristique importante permet à GHC de faire d'importantes optimisations par la suite. Cela rassure également le développeur, qui ne sera pas inquiet une seconde que la fonction 'exemple' lance un missile avant d'ajouter 2 à son entier.

    Le problème avec unsafePerformIO, c'est qu'elle permet de tromper le compilateur. la fonction foo est considérée comme pure alors que pour tout x appartenant aux entiers, foo x /== foo x !

  3. #3
    Membre averti
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Points : 346
    Points
    346
    Par défaut
    Au risque de passer pour la réincarnation de Maître Capello, je me permets de rectifier quelques abus de langages.

    Quand elle sera exécutée, elle produira un nombre entier aléatoire.
    Plus précisément : quand sa valeur de retour sera évaluée, elle produira un nombre entier aléatoire.

    Le problème avec unsafePerformIO, c'est qu'elle permet de tromper le compilateur. la fonction foo est considérée comme pure alors que pour tout x appartenant aux entiers, foo x /== foo x !
    En conséquent, on a bien

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x, y | x = y => foo x = foo y
    Ce qu’on a pas par contre, c’est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x, y | x = y => unsafePerformIO (foo x) = unsafePerformIO (foo y)
    Voilà, ça ne change pas la validité de la réponse de Yo Eight, mais je trouve que ça permet de mieux voir ce que font les monades.

  4. #4
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2009
    Messages : 97
    Points : 307
    Points
    307
    Par défaut
    @Chatanga

    J'ai peut-être mal compris ton poste mais dans la fonction foo 'unsafePerformIO hasard' sera bien exécutée sur le champ. Comme le prouve le vrai programme ci-dessous:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    module Unsafe where
     
    import System.IO.Unsafe
    import System.Random
     
    foo :: Int -> Int
    foo i = if even (unsafePerformIO randomIO :: Int) then i + 1 else i + 2
    Voici la maintenant la session GHCi qui le prouve
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    *Unsafe> foo 1 == foo 1
    False
    Les monades n'ont rien à voir la dedans

  5. #5
    Membre averti
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Points : 346
    Points
    346
    Par défaut
    Je dis effectivement n’importe quoi ! J’ai interverti les fonctions 'hasard' et 'foo' en lisant ton équation.

    Citation Envoyé par Yo Eight Voir le message
    Les monades n'ont rien à voir la dedans
    Ah bah si quand même : la fonction 'hasard' retourne bien une valeur monadique... Ou alors ce n’est pas seulement que je suis distrait, mais que je n’ai rien compris.

  6. #6
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2009
    Messages : 97
    Points : 307
    Points
    307
    Par défaut
    la fonction 'hasard' a pour type IO Int. Ceci n'est pas un type monadique. D'ailleurs cette dénomination n'a aucun sens.

    Par contre, là où je suis d'accord avec toi, c'est que IO est une instance de la classe Monad. Ce fait n'a absolument aucun rapport avec la problématique de la discussion.

    Monad n'est pas un type mais une classe. Ce n'est pas la même chose.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2009
    Messages : 38
    Points : 57
    Points
    57
    Par défaut
    Citation Envoyé par Yo Eight Voir le message
    la fonction 'hasard' a pour type IO Int. Ceci n'est pas un type monadique. D'ailleurs cette dénomination n'a aucun sens.[...]
    Monad n'est pas un type mais une classe. Ce n'est pas la même chose.
    Je pense que c'est ce que Chatanga veut dire par type monadique... un type instanciant la classe Monad. Ça me semble plein de sens compris ainsi. Non ?

  8. #8
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2009
    Messages : 97
    Points : 307
    Points
    307
    Par défaut
    Certes mais dans son premier message, il indique vouloir éviter les abus de langage.

    Dire que IO a est un type monadique est un abus de langage vu que Monad n'est pas un type mais une classe. Pour bien comprendre Haskell par la suite, il est important de bien faire la différence.

    De nombreux débutants du langage pensent que les classes en Haskell sont équivalentes aux interfaces en Java par exemple. Bien que ressemblant sur le principe, ces 2 notions sont très différentes.

  9. #9
    Membre averti
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Points : 346
    Points
    346
    Par défaut
    Je ne parle pas de type monadique, mais de valeur monadique, ce qui me semble juste pour désigner une valeur dont le type est une instance de la classe Monad. On peut même être plus compréhensif :

    Citation Envoyé par Real World Haskell
    And now, a jargon moment

    There are a few terms of jargon around monads that you may not be familiar with. These aren't formal terms, but they're in common use, so it's helpful to know about them.
    • “Monadic” simply means “pertaining to monads”. A monadic type is an instance of the Monad typeclass; a monadic value has a monadic type.
    • When we say that a type “is a monad”, this is really a shorthand way of saying that it's an instance of the Monad typeclass. Being an instance of Monad gives us the necessary monadic triple of type constructor, injection function, and chaining function.
    • In the same way, a reference to “the Foo monad” implies that we're talking about the type named Foo, and that it's an instance of Monad.
    • An “action” is another name for a monadic value. This use of the word probably originated with the introduction of monads for I/O, where a monadic value like print "foo" can have an observable side effect. A function with a monadic return type might also be referred to as an action, though this is a little less common.
    Quoiqu’il en soit, ce n’est qu’un détail. Le propos initial de mon message était de clarifier l’amalgame entre performIO et une fonction retournant une valeur de type IO (du type paramétré IO a ?), amalgame qui n’existait toutefois que dans ma tête... De plus, même si IO est un type-qui-est-une-instance-de-classe-Monad, ça n’est effectivement significatif que pour en construire une valeur ; pour l’évaluer avec performIO, sa nature monadique n’entre pas en jeu.

  10. #10
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Un autre exemple au cas où...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    import qualified Data.ByteString as B
    import System.IO.Unsafe
     
    uneString :: B.ByteString
    uneString = unsafePerformIO $ B.readFile "/proc/stat"
    Ce code te dit que uneString est une ByteString. Vu qu'il n'y a pas "d'IO" devant, si on n'avait pas la définition en dessous, on se dirait que c'est une ByteString fixe, à chaque exécution elle vaudra pareil, et même pendant la même exécution, à différent moments tu devrais pouvoir être confiant qu'elle vaudra pareil. Hé bien non.

    Et d'ailleurs, compiler ça sous Windows est encore pire, par exemple. T'as ce qui est censé être une valeur fixe qui en fait représente un plantage de ton programme au moment où ce unsafePerformIO sera exécuté!

Discussions similaires

  1. [Livres/Références] Vos avis..
    Par Community Management dans le forum Livres
    Réponses: 6
    Dernier message: 25/07/2005, 19h31
  2. Références / tutoriels MFC COM
    Par DivisionParZéro dans le forum MFC
    Réponses: 3
    Dernier message: 03/02/2004, 17h49
  3. Passage d'un tableau par référence?
    Par sebduth dans le forum C
    Réponses: 9
    Dernier message: 16/07/2003, 18h32
  4. [Concept] Table de référence
    Par matlo dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 20/01/2003, 15h01

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