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 :

question sur typage de mon module "suites mathématiques"


Sujet :

Haskell

  1. #1
    Membre régulier
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Points : 84
    Points
    84
    Par défaut question sur typage de mon module "suites mathématiques"
    Bonjour,


    je cherche à construire, à titre d'exercice pour moi, un module qui permet de faire des suites mathématiques.

    Voici ce que j'ai fait :
    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
      {-# LANGUAGE ExistentialQuantification #-}
     
      class MathSeq s where
        u_FirstTerm :: s a -> a
        u_FirstIndex :: s a -> Index
        recRelation :: s a -> (a -> a)  -- function that compute u_n+1 from the value of u_n
        u_All :: s a -> [a] -- infinite list of all terms
        u_n :: Index -> s a -> a -- nth term
        u_All seq = iterate (recRelation seq) (u_FirstTerm seq)
        u_n (Index n) seq = (u_All seq) !! n
     
      newtype Index = Index Int deriving (Show, Eq, Ord)
      instance Num Index where
          Index i1 + Index i2 = Index $ i1 + i2
     
      data ArithmeticSeq a = (Num a, Show a) => ArithmeticSeq
          {aSFirstTerm :: a,
           aSIndex :: Index,
           aSCommonDifference :: a
           }
      instance (Show a) => Show (ArithmeticSeq a) where
          show s = "ArithmeticSeq {aSFirstTerm = " ++ show (aSFirstTerm s) ++ ", aSIndex = " ++ show (aSIndex s) ++ ", aSCommonDifference = " ++ show (aSCommonDifference s) ++ "}"
     
      instance MathSeq ArithmeticSeq where
          u_FirstTerm (ArithmeticSeq ft _ _) = ft
          u_FirstIndex (ArithmeticSeq _ i _) = i
          recRelation (ArithmeticSeq _ _ cd) = (+ cd)
     
      instance (Num a) => Num (ArithmeticSeq a) where
          (+) (ArithmeticSeq ft1 i1 cd1) (ArithmeticSeq ft2 i2 cd2) = ArithmeticSeq (ft1 + ft2) (max i1 i2) (cd1 + cd2)
          (negate) (ArithmeticSeq ft i cd) = ArithmeticSeq (- ft) i (-cd)
          -- (fromInteger) (ArithmeticSeq ft i cd) = ArithmeticSeq (fromInteger ft) i (fromInteger cd)
     
      data Seq a = Seq {
            firstTerm :: a,
            firstIndex :: Index,
            recRel :: a -> a
          }
     
      syracuse = Seq 9 (Index 0) (\u_n -> if odd u_n then u_n / 2 else 3 * u_n + 1) :: Seq Int
    1. Ce qui fonctionne : tout sauf la ligne "syracuse =" en dernière ligne. La dernière ligne produit :
    No instance for (Fractional Int) arising from a use of `/'
    Possible fix: add an instance declaration for (Fractional Int)
    In the expression: u_n / 2
    In the expression: if odd u_n then u_n / 2 else 3 * u_n + 1
    In the third argument of `Seq', namely `(\ u_n -> if odd u_n then u_n / 2 else 3 * u_n + 1)'
    Comment faire fonctionner cela ? je suppose que si je déclarais en :: Seq Double, cela fonctionnerait, mais le but ici c'est bien de rester en Int


    2. Par ailleurs, il y des choses que je ne comprends pas bien :
    2.1 pourquoi le {-# LANGUAGE ExistentialQuantification #-} est-il nécessaire ? Cela ne compile pas sans cette déclaration

    2.2 pourquoi suis-je obligé de définir le "show" moi même, dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    instance (Show a) => Show (ArithmeticSeq a) where
          show s = "ArithmeticSeq {aSFirstTerm = " ++ show (aSFirstTerm s) ++ ", aSIndex = " ++ show (aSIndex s) ++ ", aSCommonDifference = " ++ show (aSCommonDifference s) ++ "}"
    en effet, le "data ArithmeticSeq" refuse le "deriving Show"

    2.3 j'ai plusieurs warnings, entre autres :
    temp.hs:39:10: Warning:
    No explicit method or default declaration for `*'
    In the instance declaration for `Num (ArithmeticSeq a)'

    (... idem pour `abs', `signum' ...)

    temp.hs:39:10: Warning:
    No explicit method or default declaration for `fromInteger'
    In the instance declaration for `Num (ArithmeticSeq a)'
    et sur le dernier, "fromInteger", je n'ai aucune idée de comment faire, ni même de pourquoi faire ... ?

    3. d'une manière générale, mon code doit être bien maladroit : des suggestions pour l'améliorer ?

    Merci !




    à noter que je suis en version 7.6.3

  2. #2
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    1) Utilise div plutôt que / pour faire une division entre entiers, div donne basiquement le quotient de la division euclidienne.


    2) 2.1) Existential n'est nécessaire ici que parce que tu as cherché à mettre des restrictions sur a dans ton type ArithmeticSeq. C'est à éviter car cela ne fait pas ce que tu penses... Laisse plutôt les contraintes aux fonctions qui manipuleront ton type et retire les de la définition du type lui-même. Si tu y tiens vraiment va voir du côté des GADTs.

    2.2) comme dit précédemment, les contraintes dans ton types ne font pas ce que tu crois. Entre autres, le "a" dans le constructeur n'est pas le même que l'argument du constructeur de type... C'est pourquoi le type n'est pas assez régulier pour que Show puisse être dérivé. Fait sauter ces contraintes et le problème disparaîtra.

    2.3) Num est une typeclass avec beaucoup de méthodes dont certaines que tu ne définis pas... Que fera Haskell lorsque tu multipliera deux ArithSeq entre elles ? Ce n'est pas une erreur de typage puisque ArithSeq est une instance de Num, mais tu n'as tout de même pas défini (*) pour ce type... Ce sera donc une erreur à l'exécution, ce qui est généralement à éviter (et pas du tout dans la philosophie de Haskell).
    fromInteger est juste une autre méthode de cette classe : tout Num devrait pouvoir s'obtenir par conversion depuis un entier (en Haskell, lorsque tu écris 5, le compilateur traduit ça par "fromInteger 5" pour que tu puisses utiliser les entiers littéraux avec n'importe quel type numérique).


    3) Quelques suggestions : ta typeclass n'apporte rien d'intéressant par rapport à ton type Seq, tu n'as pas vraiment besoin d'une typeclass ici (sauf si c'est pour t'entrainer) et ton u_n par défaut ne prend pas en compte le premier index. Pourquoi d'ailleurs avoir créé un newtype Index ? Est-ce juste pour le nom ? Dans ce cas utilise simplement un synonyme "type Index = Int".
    Ton instance Num pour ArithSeq est pleine de trous (nécessairement puisque le produit de deux suites arithmétiques n'est pas une suite arithmétique) et ne prend pas correctement en compte le cas où le premier index diffère (tu ajoutes toujours les deux premiers termes même s'ils ne sont pas de même indice). Il serait bien plus logique d'avoir une instance Num pour Seq (elle peut être complète, selon le modèle mathématique classique) et d'abandonner ArithSeq comme un type indépendant : tu peux toujours créer une fonction construisant une suite arithmétique du type Seq, si tu as besoin d'encoder le type de suite de façon plus précise remanier le type Seq pour qu'il ait plusieurs constructeurs est également plus pragmatique.

    Néanmoins un bon début.
    --
    Jedaï

  3. #3
    Membre régulier
    Inscrit en
    Mai 2005
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 140
    Points : 84
    Points
    84
    Par défaut
    ****
    Citation Envoyé par Jedai Voir le message
    Néanmoins un bon début.
    --
    Jedaï
    Merci Maître

    La réponse au point 3 va m'être très profitable, en effet, je trouvais mon code lourd et un peu "boiler plate", ce à quoi Haskell promet d'échapper. Je vais en tirer profit dans un second temps. Et oui, bien vu, j'ai un problème sur le premier indice que je définis, mais n'utilise pas : je remets cela à plus tard.

    4. dans un premier temps je vais tenir compte de tes réponses aux points 1 et 2 tout en conservant le type class. J'essaye de poser mes questions de façon très claire, mais pas d'hésitation : si pas clair, me le dire !

    Dans l'ordre :
    4.1
    Citation Envoyé par Jedai Voir le message
    1) Utilise div plutôt que / pour faire une division entre entiers, div donne basiquement le quotient de la division euclidienne.
    Effectivement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Prelude> :t (/)
    (/) :: Fractional a => a -> a -> a
    Prelude> :t div
    div :: Integral a => a -> a -> a
    D'où :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      syracuse :: Seq Int
      syracuse = Seq 9 0 (\u_n -> if odd u_n then div u_n 2 else 3 * u_n + 1)
    fonctionne, contrairement à précédemment.
    => OK.

    4.2 Je simplifie Index :
    => on gagne en simplicité, mais on perd en type safety, non ?

    4.3 Je supprime la contrainte dans le data, dont je ne maîtrise pas la portée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    data ArithmeticSeq a = ArithmeticSeq {
         aSFirstTerm :: a,
         aSIndex :: Index,
         aSCommonDifference :: a
        } deriving Show
    => le "deriving Show" fonctionne maintenant.
    => OK.

    4.4 à ce stade, le code complet est :
    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
     
      -- ce code ne type check pas !!
     
      class MathSeq s where
        u_FirstTerm :: s a -> a
        u_FirstIndex :: s a -> Index
        recRelation :: s a -> (a -> a) -- function that compute u_n+1 from the value of u_n
        u_All :: s a -> [a] -- infinite list of all terms
        -- u_n :: Index -> s a -> a -- nth term
        u_All seq = iterate (recRelation seq) (u_FirstTerm seq)
        -- u_n (Index n) seq = (u_All seq) !! n
     
      type Index = Int
     
      data ArithmeticSeq a = ArithmeticSeq {
           aSFirstTerm :: a,
           aSIndex :: Index,
           aSCommonDifference :: a
          } deriving Show
      instance MathSeq ArithmeticSeq where
          u_FirstTerm (ArithmeticSeq ft _ _) = ft
          u_FirstIndex (ArithmeticSeq _ i _) = i
          recRelation (ArithmeticSeq _ _ cd) = (+ cd)
      instance (Num a) => Num (ArithmeticSeq a) where
          (+) (ArithmeticSeq ft1 i1 cd1) (ArithmeticSeq ft2 i2 cd2) = ArithmeticSeq (ft1 + ft2) (max i1 i2) (cd1 + cd2)
          (negate) (ArithmeticSeq ft i cd) = ArithmeticSeq (- ft) i (-cd)
     
      data Seq a = Seq {
            firstTerm :: a,
            firstIndex :: Index,
            recRel :: a -> a
          }
      instance MathSeq Seq where
          u_FirstTerm s = firstTerm s
          u_FirstIndex s = firstIndex s
          recRelation s = recRel s
     
      data OtherSeq a = OtherSeq a Index (a -> a) -- just to test the simple form
     
      syracuse :: Seq Int
      syracuse = Seq 9 0 (\u_n -> if odd u_n then div u_n 2 else 3 * u_n + 1)
    mais le code ne typecheck pas :
    No instance for (Num a) arising from a use of `+'
    Possible fix:
    add (Num a) to the context of the type signature for recRelation :: ArithmeticSeq a -> a -> a
    In the expression: (+ cd)
    In an equation for `recRelation': recRelation (ArithmeticSeq _ _ cd) = (+ cd)
    In the instance declaration for `MathSeq ArithmeticSeq'
    Failed
    Suivons donc le conseil du compilateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    instance MathSeq ArithmeticSeq where
        u_FirstTerm (ArithmeticSeq ft _ _) = ft
        u_FirstIndex (ArithmeticSeq _ i _) = i
        recRelation :: (Num a) => ArithmeticSeq a -> (a -> a)
        recRelation (ArithmeticSeq _ _ cd) = (+ cd)
    :23:20:
    Illegal type signature in instance declaration:
    recRelation :: Num a => ArithmeticSeq a -> (a -> a)
    (Use -XInstanceSigs to allow this)
    In the instance declaration for `MathSeq ArithmeticSeq'
    Failed
    => Mauvaise pioche, mais pourquoi ?

    Je reviens donc en arrière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    instance MathSeq ArithmeticSeq where
        u_FirstTerm (ArithmeticSeq ft _ _) = ft
        u_FirstIndex (ArithmeticSeq _ i _) = i
        -- recRelation :: (Num a) => ArithmeticSeq a -> (a -> a)
        recRelation (ArithmeticSeq _ _ cd) = (+ cd)
    et je modifie maintenant :
    - la type class
    - je complète ma définition de instance (Num a) => Num (ArithmeticSeq a)

    D'où le code complet, qui type-checks :
    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
     
      class MathSeq s where
        u_FirstTerm :: s a -> a
        u_FirstIndex :: s a -> Index
        recRelation :: (Num a) => s a -> (a -> a) -- function that compute u_n+1 from the value of u_n
        u_All :: (Num a) => s a -> [a] -- infinite list of all terms
        u_All seq = iterate (recRelation seq) (u_FirstTerm seq)
     
      type Index = Int
     
      data Seq a = Seq {
            firstTerm :: a,
            firstIndex :: Index,
            recRel :: a -> a
          }
      instance MathSeq Seq where
          u_FirstTerm s = firstTerm s
          u_FirstIndex s = firstIndex s
          recRelation s = recRel s
     
      data ArithmeticSeq a = ArithmeticSeq {
           aSFirstTerm :: a,
           aSIndex :: Index,
           aSCommonDifference :: a
          } deriving (Show, Eq)
      instance MathSeq ArithmeticSeq where
          u_FirstTerm (ArithmeticSeq ft _ _) = ft
          u_FirstIndex (ArithmeticSeq _ i _) = i
          recRelation (ArithmeticSeq _ _ cd) = (+ cd)
      instance (Num a) => Num (ArithmeticSeq a) where
          (+) (ArithmeticSeq ft1 i1 cd1) (ArithmeticSeq ft2 i2 cd2) = ArithmeticSeq (ft1 + ft2) (max i1 i2) (cd1 + cd2)
          (negate) (ArithmeticSeq ft i cd) = ArithmeticSeq (- ft) i (-cd)
          -- the following does not work : (*) k (ArithmeticSeq u_first i r) = ArithmeticSeq (k * u_first) i (k * r)
          (abs) (ArithmeticSeq u_first i r) = ArithmeticSeq (abs u_first) i (abs r)
          (signum) (ArithmeticSeq u_first i r) = ArithmeticSeq (signum u_first) i (signum r)
          -- the following does not work : (fromInteger) (ArithmeticSeq u_first i r) = ArithmeticSeq (fromInteger u_first) i (fromInteger r)
     
      syracuse :: Seq Int
      syracuse = Seq 9 0 (\u_n -> if odd u_n then div u_n 2 else 3 * u_n + 1)
    => il me reste (ci-dessous) 2 warnings : comment m'en débarrasser ?
    :32:10: Warning:
    No explicit method or default declaration for `*'
    In the instance declaration for `Num (ArithmeticSeq a)'

    :32:10: Warning:
    No explicit method or default declaration for `fromInteger'
    In the instance declaration for `Num (ArithmeticSeq a)'
    Ok

  4. #4
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    4.2) La perte est très relative vu que la plupart de tes types de suites sont de toute façon polymorphiques en "a" et que tu ne peux donc mêler "a" et "Int=Index" sans conversion explicite de toute façon. Le newtype ici n'apporte pas assez comparé à son cout en complexité du code.

    4.4) L'ensemble de tes problèmes provient de la définition de ta classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class MathSeq s where
        u_FirstTerm :: s a -> a
        u_FirstIndex :: s a -> Index
        recRelation :: s a -> (a -> a) -- function that compute u_n+1 from the value of u_n
        u_All :: s a -> [a] -- infinite list of all terms
        -- u_n :: Index -> s a -> a -- nth term
        u_All seq = iterate (recRelation seq) (u_FirstTerm seq)
        -- u_n (Index n) seq = (u_All seq) !! n
    Cette définition affirme que tu pourras toujours déclarer une instance de MathSeq pour "s" contenant absolument n'importe quel type "a". Or ce n'est pas le cas pour tes suites arithmétiques qui n'ont de sens que pour un "a" instance de Num.

    Tu as donc "réglé" le problème en ajoutant une contrainte "Num a" aux méthodes de ta classe mais du coup tu en restreins la généralité : ta classe ne pourra plus être utilisée qu'avec des suites numériques, pas des suites de fonctions, ou d'ensembles ou... Toute suites parfaitement légitimes d'un point de vue mathématiques (note que ta classe se restreint déjà aux suites définies par récurrence simple mais c'est un autre problème).

    Ce que tu veux vraiment faire, c'est donner la possibilité de ne déclarer des instances de ArithSeq que pour des "a" numériques mais en gardant la classe d'origine complètement polymorphique en le type des termes. Ce n'est pas possible avec ta déclaration d'origine car tu ne parles pas du tout de "a" dans "class MathSeq s where" donc il est impossible de contraindre quelque chose sur lequel tu n'as aucune prise.
    Il existe deux solutions à ce problème : les classes à plusieurs paramètres associées aux dépendances fonctionnelles ou les familles de type. Je recommande les familles de type comme l'approche la plus moderne et à l'aspect plus fonctionnel. Ta classe devient alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MathSeq sa where
        type Term sa :: *
        u_FirstTerm :: sa -> Term sa
        u_FirstIndex :: sa -> Index
        recRelation :: sa -> (Term sa -> Term sa) -- function that compute u_n+1 from the value of u_n
        u_All :: sa -> [Term sa] -- infinite list of Term sall terms
        u_All seq = iterate (recRelation seq) (u_FirstTerm seq)
    J'ai changé le nom du paramètre en "sa" pour souligner le fait qu'on n'a plus affaire à un constructeur de type mais bien à un type concret, contenant a. "type Term sa :: *" déclare que pour chaque instance il faudra déclarer le type du contenu, sous le nom de de "Term sa". Cette classe est plus flexible que ton original, elle peut entre autre être instancié pour un type ne prenant pas de paramètre, spécialisé pour un type concret de termes, une suite de Double par exemple.

    Une instance classique ressemblera à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    instance MathSeq (Seq a)  where
        type Term (Seq a) = a
        u_FirstTerm s = firstTerm s
        u_FirstIndex s = firstIndex s
        recRelation s = recRel s
    Peu de changement mais l'instance est maintenant "Seq a" au lieu de "Seq".

    On voit que le "a" fait partie du paramètre, on a donc prise sur ce "a" et on peut par exemple le contraindre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    instance (Num a) => MathSeq (ArithmeticSeq a) where
        type Term (ArithmeticSeq a) = a         
        u_FirstTerm (ArithmeticSeq ft _ _) = ft
        u_FirstIndex (ArithmeticSeq _ i _) = i
        recRelation (ArithmeticSeq _ _ cd) = (+ cd)
    Il faudra rajouter cette extension au début du fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    {-# LANGUAGE TypeFamilies #-}
    Cette extension fait partie de celles qui seront probablement incluses dans Haskell à terme mais pour l'instant...

    4.5) Ton type ArithmeticSeq ne respecte pas vraiment le contrat de Num. On peut éviter les warnings, mais on est alors obligé de mettre des méthodes qui débouchent sur des erreurs à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    instance (Num a) => Num (ArithmeticSeq a) where
        -- Toujours un problème avec (ft1 + ft2) si i1 /= i2
        (+) (ArithmeticSeq ft1 i1 cd1) (ArithmeticSeq ft2 i2 cd2) = ArithmeticSeq (ft1 + ft2) (max i1 i2) (cd1 + cd2)
        (negate) (ArithmeticSeq ft i cd) = ArithmeticSeq (- ft) i (-cd)
        fromInteger n = ArithmeticSeq (fromInteger n) 0 0 -- faisons une suite constante
        _ * _ = error "Le produit de deux suites arithmétiques n'est pas une suite arithmétique"
        abs _ = error "La valeur absolue d'une suite arithmétique n'est pas toujours arithmétique"
        signum _ = error "???"
    Ta suite de Syracuse a également un petit problème, elle divise par 2 lorsque le terme est impair (odd) au lieu de pair (even).
    --
    Jedaï

Discussions similaires

  1. question sur une page de module
    Par kate59 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 12/09/2011, 19h08
  2. [1.x] Question sur les relations mon schéma
    Par Calvein dans le forum Symfony
    Réponses: 3
    Dernier message: 11/06/2010, 15h32
  3. Question sur eval dans mon code javascript
    Par beegees dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 27/04/2009, 10h44
  4. question sur les tables du module SD (et mm)
    Par verbatim56 dans le forum SAP
    Réponses: 13
    Dernier message: 26/06/2007, 22h41

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