Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 10 sur 10
  1. #1
    Invité de passage
    Inscrit en
    novembre 2012
    Messages
    1
    Détails du profil
    Informations forums :
    Inscription : novembre 2012
    Messages : 1
    Points : 0
    Points
    0

    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 confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    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 : 98
    Points : 280
    Points
    280

    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 :
    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 :
    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 confirmé
    Avatar de Chatanga
    Inscrit en
    décembre 2005
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : décembre 2005
    Messages : 184
    Points : 260
    Points
    260

    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 :
    x, y | x = y => foo x = foo y
    Ce qu’on a pas par contre, c’est :

    Code :
    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 confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    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 : 98
    Points : 280
    Points
    280

    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 :
    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 :
    1
    2
    3
    *Unsafe> foo 1 == foo 1
    False
    Les monades n'ont rien à voir la dedans

  5. #5
    Membre confirmé
    Avatar de Chatanga
    Inscrit en
    décembre 2005
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : décembre 2005
    Messages : 184
    Points : 260
    Points
    260

    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 confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    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 : 98
    Points : 280
    Points
    280

    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
    Inscrit en
    août 2009
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : août 2009
    Messages : 38
    Points : 48
    Points
    48

    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 confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2009
    Messages
    98
    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 : 98
    Points : 280
    Points
    280

    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 confirmé
    Avatar de Chatanga
    Inscrit en
    décembre 2005
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : décembre 2005
    Messages : 184
    Points : 260
    Points
    260

    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 Confirmé Sénior
    Avatar de Alp
    Homme Profil pro
    Inscrit en
    juin 2005
    Messages
    8 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : juin 2005
    Messages : 8 586
    Points : 10 409
    Points
    10 409

    Par défaut

    Un autre exemple au cas où...

    Code :
    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é!

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •