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 :

Iteration d'une fonction monadique


Sujet :

Haskell

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut Iteration d'une fonction monadique
    Bonjour,

    Je découvre petit à petit Haskell et me voila confronté aux monads ...

    Considérons une première fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    foo :: State Bool ()
    foo = do b <- get
                 if (b == True) then foo else put b
    Maintenant, je voudrais effectuer la même chose mais le type de la fonction est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    foo2 :: IO (State Bool ())
    Et la, je bloque.
    Pourriez vous m'aider à itérer une fonction de ce type ?

    Merci d'avance.

  2. #2
    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
    Hmm...
    Qu'est-ce qui te pose concrètement problème ?
    Simplement de devoir plonger ta "fonction" (et donc son appel à elle-même) dans la monade IO ?

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut
    Je ne cherche pas à "plonger" la fonction foo dans IO.

    La fonction foo est récursive. La condition d'arrêt dépend de la valeur contenu dans la monade State.
    Dans le même esprit, je cherche à écrire une fonction recursive du type foo2, dont la condition d'arrêt dépend de la valeur contenue dans State qui est elle même est dans IO.

    J'espère être plus clair

  4. #4
    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
    Tu as essayé, fait une tentative déjà ?

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut
    Oui, j'ai essayé.
    Mais j'ai toujours "une monade de trop".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    foo2 :: IO ( State Bool ())
    foo2 = do l <- getChar c
              return $ do b <- get
                          if b then put b else foo2
    Et évidement, le type attendu pour l'expression dans le else est State Bool () alors que le type est celui de foo2.

    Voila où j'en suis.

    Noter que ce code est un exemple de ma situation. Il ne faut donc pas lui preter la moindre utilité, mais je pense qu'il reflète bien mon problème réel.

  6. #6
    Inactif  
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    1 958
    Détails du profil
    Informations personnelles :
    Âge : 58
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 958
    Points : 2 467
    Points
    2 467
    Par défaut
    Ta situation n'est vraiment pas clair.
    Par exemple le premier code ne peut pas marche car « l » n'est pas déclaré. M'est avis que ton exemple est aussi plus compliqué que celui que tu nous montres. Il est difficile de te répondre lorsqu'on ne connait pas vraiment le problème. Tu sembles dire que c'est une erreur de typage. Il faudrait donc voir ta fonction.

  7. #7
    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
    Citation Envoyé par kg2007 Voir le message
    Oui, j'ai essayé.
    Mais j'ai toujours "une monade de trop".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    foo2 :: IO ( State Bool ())
    foo2 = do l <- getChar c
              return $ do b <- get
                          if b then put b else foo2
    Et évidement, le type attendu pour l'expression dans le else est State Bool () alors que le type est celui de foo2.

    Voila où j'en suis.

    Noter que ce code est un exemple de ma situation. Il ne faut donc pas lui preter la moindre utilité, mais je pense qu'il reflète bien mon problème réel.
    Es-tu sûr d'avoir mis le return au bon endroit ?
    En effet, c'est le put b qui déterminera le type de ton expression. Peut-être que cela peut t'aider.

    Garulfo > pas besoin de déclarer l ni b avant dans ce genre situations en Haskell, ils résultent d'une action dans une monade.

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut
    Par exemple le premier code ne peut pas marche car « l » n'est pas déclaré.
    Navré, j'ai corrigé.

    Un autre exemple:
    Le module Monad.Loops (http://hackage.haskell.org/packages/...3AiterateWhile) définit la fonction iterateWhile ayant le type suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    iterateWhile :: Monad m => (a -> Bool) -> m a -> m a
    Je cherche à écrire un fonction ayant le même comportement mais dont le type est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    iterateWhileBis :: (Monad m,Monad n) => (a -> Bool) -> m (n a) -> m (n a)
    Pourriez vous essayer d'écrire une telle fonction ?

  9. #9
    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
    Il n'y a pas besoin.

    Dans le cas de iterateWhile, tu as m a. Mais ici, a peut très bien être un certain type n a où n est une autre monade que M.

    Bref, ça devrait aller

  10. #10
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut
    Ce n'est pas tout à fait pareil.

    Le signature de la fonction qu tu evoques est la suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (Monad m,Monad n) => (n a -> Bool) -> m (n a) -> m (n a)
    Et une fonction de signature
    ce n'est pas évident ...

    La signature de la fonction que je cherche à réaliser est la suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (Monad m,Monad n) => (a -> Bool) -> m (n a) -> m (n a)

  11. #11
    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
    Citation Envoyé par kg2007 Voir le message
    Je ne cherche pas à "plonger" la fonction foo dans IO.

    La fonction foo est récursive. La condition d'arrêt dépend de la valeur contenu dans la monade State.
    Dans le même esprit, je cherche à écrire une fonction recursive du type foo2, dont la condition d'arrêt dépend de la valeur contenue dans State qui est elle même est dans IO.

    J'espère être plus clair
    Ton type est incorrect, ici ce que tu as c'est une action IO qui retourne une action dans la monade State... Il n'y a donc pas d'état persistant au fil des itérations de cette fonction comme c'est sans doute ton objectif.

    Pour faire ça il faut utiliser les transformateurs de monades :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    foo2 :: StateT Bool IO ()
    foo2 = do 
       l <- liftIO $ getChar
       b <- get
       if b then put b else foo2
    (Non que cette fonction en particulier ait un intérêt quelconque... Je préfèrerais que tu nous dises ce que tu essaies réellement de faire)

    --
    Jedaï

  12. #12
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut
    J'avais pensé à utiliser des transformateurs, mais cela me gène car je dois "intégrer" IO dans l'état alors que celui ci n'en dépend pas.

    Pour préciser mon application:
    J'ai un état. J'applique des opérations sur cet état. Jusqu'ici tout va bien. Mais ensuite je souhaiterais appliquer ces opérations dans un ordre aléatoire, d'où l'apparition de IO.
    Les opérations modifiant l'état ne nécessite pas d'IO, seul l'ordre dans lequel je les applique en dépend, c'est pourquoi le type StateT n'est pas nécessaire.

    En pseudo code.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    op1 :: State Bool ()
    op1 = return ()
     
    op2 :: State Bool ()
    op2 = return ()  -- En vrai, on fait des choses ...
     
    run :: IO (State Bool ())
    run = do s <- newStdGen
                 appliquer op1 ou op2 aléatoirement
                 si l'état ne convient pas reapliquer run
    Voila un peu plus à quoi ressemble mon application.


    Après reflexion ... je crois que l'exemple iterateWhileBis illustre bien le problème.
    Est-il possible d'écrire une telle fonction ?
    Ou est necessaire d'utiliser des transformateurs ?

  13. #13
    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
    Pour faire de l'aléatoire, tu n'as pas besoin d'IO, tu as juste besoin d'une monade pour l'aléatoire. Quelque chose comme MonadRandom (basique, reprend les idées et l'implémentation de System.Random) ou monte-carlo (plus rapide, interface différente, nécessite la librairie GSL) ou autres (tu as des trucs assez complexes sur Hackage, capable de traiter des distributions avancées). Ensuite tu peux l'utiliser dans StateT ou utiliser le transformeur associé autour de State au choix.

    NB : IO est cependant toujours nécessaire pour créer le générateur aléatoire (du moins si tu veux qu'il change d'une exécution à l'autre).

    Une autre approche est de créer d'avance les valeurs aléatoires que tu utiliseras dans ton State, tu peux même en créer une quantité infinie si le nombre dont tu auras besoin n'est pas fixé au départ.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    foo :: IO (State Int ())
    foo = do
        g <- newStdGen
        return . st . randomRs (False, True) $ g
      where
        st (b:bs) = do
          modify (+1)
          if b then st bs else return ()
    --
    Jedaï

  14. #14
    Inactif  
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    1 958
    Détails du profil
    Informations personnelles :
    Âge : 58
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 958
    Points : 2 467
    Points
    2 467
    Par défaut
    Citation Envoyé par Alp Voir le message
    [...]
    Garulfo > pas besoin de déclarer l ni b avant dans ce genre situations en Haskell, ils résultent d'une action dans une monade.
    Vu la réponse de notre nouveau participant, il me semble que j'avais raison

    J'avais l'impression que l'erreur de typage venait du «*put » mais étant donné qu'on avait peut-être une fonction bidon devant nous, il était difficile d'être définitif.

    En tout cas…

  15. #15
    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
    Citation Envoyé par Garulfo Voir le message
    Vu la réponse de notre nouveau participant, il me semble que j'avais raison

    J'avais l'impression que l'erreur de typage venait du «*put » mais étant donné qu'on avait peut-être une fonction bidon devant nous, il était difficile d'être définitif.

    En tout cas…
    Le put n'était pas responsable de l'erreur de typage, il était du type correct d'après la signature de la fonction : State Bool (). Par contre foo2 dans la seconde branche du if/then/else n'est pas du bon type : il devrait avoir le même type que "put b" mais a le type IO (State Bool ())...

    --
    Jedaï

  16. #16
    Inactif  
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    1 958
    Détails du profil
    Informations personnelles :
    Âge : 58
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 958
    Points : 2 467
    Points
    2 467
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Le put n'était pas responsable de l'erreur de typage, il était du type correct d'après la signature de la fonction : State Bool (). Par contre foo2 dans la seconde branche du if/then/else n'est pas du bon type : il devrait avoir le même type que "put b" mais a le type IO (State Bool ())...

    --
    Jedaï
    Oui enfin dire que les deux ne concordent pas n'est-ce pas dire la même chose ?

    Parce que la signature de la fonction est IO (State Bool()) comme tu le dis. Donc dire que c'est « du type correct d'après la signature de la fonction : State Bool () » c'est un peu contradictoire non ?

    En tout cas, vu que la fonction semblait être un exemple et non LA fonction, il me semblait peu pertinent de faire une remarque là.

  17. #17
    Candidat au Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 7
    Points : 2
    Points
    2
    Par défaut
    Merci beaucoup.
    Le passage par liste infinie débloque ma situation de facon acceptable.

    Il faut que j'avance un peu dans mon code ... C'est pourquoi je ne peux m'attarder plus longtemps la dessus ... mais j'y reviendrai ...
    car j'aimerais bien comprendre pourquoi je n'arrive pas à coder iterateWhileBis.

    Merci encore,
    A bientot

    (PS : C'est dommage qu'il n'y ait pas un bouton +ou- résolu )

  18. #18
    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
    Citation Envoyé par Garulfo Voir le message
    Parce que la signature de la fonction est IO (State Bool()) comme tu le dis. Donc dire que c'est « du type correct d'après la signature de la fonction : State Bool () » c'est un peu contradictoire non ?

    En tout cas, vu que la fonction semblait être un exemple et non LA fonction, il me semblait peu pertinent de faire une remarque là.
    Il y avait un return (dans la monade IO) devant cette expression, donc le type State Bool () était bien le type correct pour cette expression d'après la signature de la fonction. Néanmoins comme tu le dis cette fonction n'était qu'un exemple et n'avait guère de sens.

    Citation Envoyé par kg2007 Voir le message
    car j'aimerais bien comprendre pourquoi je n'arrive pas à coder iterateWhileBis.
    Le type est réalisable, mais il te manque la première pierre pour coder cette fonction : que doit-elle faire exactement ? Je ne suis pas sûr qu'il soit possible de créer une "itération" intéressante de ton point de vue avec un tel type.

    --
    Jedaï

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 16/03/2015, 21h13
  2. [11gR2] Une iteration dans une fonction
    Par Invité dans le forum PL/SQL
    Réponses: 6
    Dernier message: 15/03/2013, 20h00
  3. passer un iterator en argument d'une fonction
    Par manitor dans le forum SL & STL
    Réponses: 3
    Dernier message: 13/09/2009, 14h42
  4. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14
  5. Une fonction avec des attributs non obligatoires
    Par YanK dans le forum Langage
    Réponses: 5
    Dernier message: 15/11/2002, 13h39

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