Précédent   Forum du club des développeurs et IT Pro > Autres langages > Langages fonctionnels > Haskell
Haskell Forum d'entraide sur la programmation en langage fonctionnel Haskell
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 20/11/2012, 14h04   #1
roydu06
Invité de passage
 
Inscription : 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.
roydu06 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/11/2012, 10h45   #2
Yo Eight
Membre confirmé
 
Homme
Ingénieur développement logiciels
Inscription : mai 2009
Messages : 89
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 : 89
Points : 285
Points : 285
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 !
Yo Eight est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/11/2012, 21h11   #3
Chatanga
Membre confirmé
 
Avatar de Chatanga
 
Inscription : décembre 2005
Messages : 165
Détails du profil
Informations forums :
Inscription : décembre 2005
Messages : 165
Points : 233
Points : 233
Au risque de passer pour la réincarnation de Maître Capello, je me permets de rectifier quelques abus de langages.

Citation:
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.

Citation:
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.
Chatanga est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/11/2012, 22h57   #4
Yo Eight
Membre confirmé
 
Homme
Ingénieur développement logiciels
Inscription : mai 2009
Messages : 89
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 : 89
Points : 285
Points : 285
@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
Yo Eight est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2012, 06h32   #5
Chatanga
Membre confirmé
 
Avatar de Chatanga
 
Inscription : décembre 2005
Messages : 165
Détails du profil
Informations forums :
Inscription : décembre 2005
Messages : 165
Points : 233
Points : 233
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.
Chatanga est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2012, 10h09   #6
Yo Eight
Membre confirmé
 
Homme
Ingénieur développement logiciels
Inscription : mai 2009
Messages : 89
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 : 89
Points : 285
Points : 285
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.
Yo Eight est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2012, 17h08   #7
ceciestunpseudo
Membre du Club
 
Inscription : août 2009
Messages : 38
Détails du profil
Informations forums :
Inscription : août 2009
Messages : 38
Points : 51
Points : 51
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 ?
ceciestunpseudo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2012, 19h49   #8
Yo Eight
Membre confirmé
 
Homme
Ingénieur développement logiciels
Inscription : mai 2009
Messages : 89
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 : 89
Points : 285
Points : 285
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.
Yo Eight est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/12/2012, 07h36   #9
Chatanga
Membre confirmé
 
Avatar de Chatanga
 
Inscription : décembre 2005
Messages : 165
Détails du profil
Informations forums :
Inscription : décembre 2005
Messages : 165
Points : 233
Points : 233
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.
Chatanga est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/12/2012, 11h07   #10
Alp
Rédacteur
 
Avatar de Alp
 
Homme
Inscription : juin 2005
Messages : 8 586
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 24
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : juin 2005
Messages : 8 586
Points : 11 172
Points : 11 172
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é!
Alp est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 18h11.


 
 
 
 
Partenaires

Hébergement Web