Coder-Studio - Forums

Vous n'êtes pas identifié.

#1 15-11-2009 19:03:21

Calvin1602
Administrateur
Lieu: Rennes
Date d'inscription: 15-04-2005
Messages: 2262
Site web

idiomes de prog en Haskell

Ce message est, vous le comprendrez bien vite, destiné prioritairement à Alp, mais pourquoi ne pas vous en faire profiter ? 003_wink

Je suis tombé sur Real World Haskell à la bibliothèque l'autre jour, et vu la pub qu'on a dessus sur le blog, je l'ai pris afin de ne pas mourir idiot. Et aussi parce que je me disais que, connaissant un peu l'OCaml, ça devrait pas être trop dur.

Je comprends à peu près tout ce que le bouquin dit, j'arrive à faire des trucs simples, les mêmes que je sais faire en Caml. Genre, parcourir une liste ou ce genre de connerie.

Maintenant, j'ai voulu faire le même "hello world" que j'avais posté il y a longtemps pour Lua/LuaBind : une classe Player avec quelques champs et un PlayerManager qui les gère.

Code:

-- "record syntax", je trouve ça plus clair
data TPlayer = Player {
        munitions :: Int,
        nom :: String
    }
    deriving (Show) -- Ça c'est THE killer feature omg

-- syntaxe normale, j'ai pas besoin de plus.
data TPlayerManager = PlayerManager [TPlayer] -- C'est une simple liste de TPlayer
    deriving (Show)

(Pour la forme, j'ai nommé les types et les constructeurs différemment)

Bon. Maintenant, je veux une fonction play qui m'enlève une cartouche. Ah. Problème.
- les données sont "immutables" en Haskell. Donc je suis obligé de reconstuire un Player identique, mais avec une munition en moins. Je n'ai pas (encore) trouvé le moyen de faire ça proprement.
- Je n'ai pas trouvé comment ajouter des fonctions membres. Ni dans la CHeatSheet, ni dans le bouquin. Ce qui me porte à penser que mon approche est mauvaise de A à Z.

Code:

play p@(Player {munitions = m, nom = n}) =
    if m>0
    then Player (m-1) n
    else p

C'est ignoblissime. Là je n'ai que deux membres donc ça va, mais si j'en avais 100, je serais obligé de déconstruire les 100 membres avec le @, et de les reconstuire après. Là encore, soit ya plus simple, soit j'applique au Haskell des idiomes de C++ et c'est mal, soit Haskell c'est tout pourri.

bref, je peux écrire ça :

Code:

main = print (
        play (Player 100 "Calvin")
    )

ça fait ce que ça doit faire.

Maintenant, j'aimerais faire une fonction playall qui fasse un forall sur la liste de TPlayer de PlayerManager. Ce que j'ai naturellement écrit comme ça :

Code:

playall pm = map play pm

mais là :     Couldn't match expected type `[TPlayer]'
           against inferred type `TPlayerManager'

voilà ...

Pour le PlayerManager je sens que je ne suis pas très loin, mais pour le Player, j'ai l'impression que ça ne va pas du tout.

Aide, remarques et commentaires débiles bienvenus 016_lol


_________________________________________________________
Remember, raptors run at 10m/s and do not know fear.
http://membres.lycos.fr/Arnaud1602/CalvinhobbesLogo.gif

Hors ligne

 

#2 17-11-2009 01:22:41

Alp
Membre
Lieu: Marseille
Date d'inscription: 25-04-2006
Messages: 153
Site web

Re: idiomes de prog en Haskell

Hello,

Calvin1602 a écrit:

Ce message est, vous le comprendrez bien vite, destiné prioritairement à Alp, mais pourquoi ne pas vous en faire profiter ? 003_wink

T'as bien eu raison. Comme ça si d'autres se mettent à Haskell... 039_rolleyes

Calvin1602 a écrit:

Je suis tombé sur Real World Haskell à la bibliothèque l'autre jour, et vu la pub qu'on a dessus sur le blog, je l'ai pris afin de ne pas mourir idiot. Et aussi parce que je me disais que, connaissant un peu l'OCaml, ça devrait pas être trop dur.

'tention, y'a pas un gouffre entre les deux, mais bon 006_grin

Calvin1602 a écrit:

Je comprends à peu près tout ce que le bouquin dit, j'arrive à faire des trucs simples, les mêmes que je sais faire en Caml. Genre, parcourir une liste ou ce genre de connerie.

Maintenant, j'ai voulu faire le même "hello world" que j'avais posté il y a longtemps pour Lua/LuaBind : une classe Player avec quelques champs et un PlayerManager qui les gère.

Ok. Mais avant qu'on cause du code, je t'arrête.
En Haskell, tu bannis le terme "classe" 006_grin Enfin, dans ce contexte-là. En Haskell, t'as les "type classes" et c'est tout ce à quoi on peut référer en disant "class", même si on utilise en général carrément "typeclass" plutôt que "class".

En Haskell, t'as 3 types de données, en gros.
- type algébrique, du genre : data direction = Up | Down | Left | Right ou encore data Maybe a = Nothing | Just a
- type 'record' : data Personne = Personne { age :: Integer, prenom :: String, nom :: String }
- type tuple : data Point3D = Point3D Double Double Double

A côté de ça, t'as 3 façons de déclarer des types : data, type et newtype, chacune avec leur utilisation.
Cf http://www.haskell.org/haskellwiki/Type

Calvin1602 a écrit:

Bon. Maintenant, je veux une fonction play qui m'enlève une cartouche. Ah. Problème.
- les données sont "immutables" en Haskell. Donc je suis obligé de reconstuire un Player identique, mais avec une munition en moins. Je n'ai pas (encore) trouvé le moyen de faire ça proprement.
- Je n'ai pas trouvé comment ajouter des fonctions membres. Ni dans la CHeatSheet, ni dans le bouquin. Ce qui me porte à penser que mon approche est mauvaise de A à Z.

Etant donné que ce ne sont pas des classes, tu n'as pas de fonctions membres. Ton type de données va encapsuler des données, et tu vas ensuite définir des fonctions qui constitueront ce que l'on appellerait son "interface" en OO, qui permettront de le manipuler. (et le fait de mettre un "attribut" dans ton type qui soit une fonction n'en fait pas une fonction membre, c'est vraiment un attribut quoi).

Calvin1602 a écrit:

Code:

play p@(Player {munitions = m, nom = n}) =
    if m>0
    then Player (m-1) n
    else p

C'est ignoblissime. Là je n'ai que deux membres donc ça va, mais si j'en avais 100, je serais obligé de déconstruire les 100 membres avec le @, et de les reconstuire après. Là encore, soit ya plus simple, soit j'applique au Haskell des idiomes de C++ et c'est mal, soit Haskell c'est tout pourri.

En fait, quand tu définis un type avec le style 'record', donc genre ton Player, tu as quelque chose qui se fait automatiquement... Pour chacun des champs, tu as une fonction 'Player -> TypeDuChamps' qui est automatiquement crée, et qui porte le même nom que le champs.
Donc là genre tu peux faire, si p est de type Player :

Code:

munitions p

et ça te renvoie le nombre de munitions de ton Player.
Du coup, ta fonction play devient :

Code:

play p = let m = munitions p in 
                     if m > 0 then Player (m-1)  (nom p)
                     else p

Mais il y a une façon de ne modifier qu'un nombre fini de champs d'un record, c'est en faisant :

Code:

monInstance { attr1 = foo1, attr2 = foo2 }

ça va retourner monInstance, mais en ayant mis la valeur de attr1 à foo1 et la valeur de attr2 à foo2. Attention, ça ne modifie pas monInstance, ç'en retourne une nouvelle avec les updates demandés.
Du coup, ta fonction play peut aussi s'écrire :

Code:

play p = let m = munitions p in 
                     if m > 0 then p { munitions = m-1 } -- tout peut même être résumé à p { munitions = if m > 0 then m-1 else m } je pense
                     else p

Calvin1602 a écrit:

Maintenant, j'aimerais faire une fonction playall qui fasse un forall sur la liste de TPlayer de PlayerManager. Ce que j'ai naturellement écrit comme ça :

Code:

playall pm = map play pm

mais là :     Couldn't match expected type `[TPlayer]'
           against inferred type `TPlayerManager'

voilà ...

Le fait est que tu as utilisé data pour définir TPlayerManager. Et même s'il n'y a qu'un type sous-jacent, un TPlayerManager n'est pas pareil que [Player].
Je te conseille de re-regarder la page sur les types en haskell dont j'ai donné le lien plus haut.
En particulier, si tu veux vraiment faire un bête synonyme de [Player], il faut utiliser 'type'. Newtype permet juste de vraiment faire un nouveau type, pas un bête synonyme, sans introduire d'overhead au runtime comme le fait data. En gros c'est vraiment un nouveau type pour le système de type mais tu dis au compilo 'mon gars, te prends pas la tête, en fait ça encapsule juste <le type sous-jacent>'.
Bref, si tu changes ta déclaration de TPlayerManager en :

Code:

type TPlayerManager = [Player]

ça marchera.
Sinon t'es obligé de faire une fonction qui récupère la liste sous jacente depuis un TPlayerManager, genre

Code:

getPlayerList (PlayerManager playerList) = playerList

Mais de toute manière la page wiki que je t'ai donnée devrait vraiment t'éclairer sur tout ça.

Calvin1602 a écrit:

Aide, remarques et commentaires débiles bienvenus 016_lol

J'ai surement mis un peu de tout 006_grin

Je pense avoir répondu à toutes tes questions mais si j'ai oublié quelque chose ou si d'autres te viennent n'hésite pas. Et si je mets trop de temps, ping moi par mail 006_grin

Hors ligne

 

#3 17-11-2009 07:45:13

Calvin1602
Administrateur
Lieu: Rennes
Date d'inscription: 15-04-2005
Messages: 2262
Site web

Re: idiomes de prog en Haskell

Wahou, merci 001_smile
...pour :
- " munitions p ", parce que j'ai vu ça nulle part et que quand même c'est la moindre des choses
- monInstance { attr1 = foo1, attr2 = foo2 }, qui m'évite pas mal de boulot 001_smile
- Le petit lien sur les types, qui est plus clair que ce que j'ai pu voir dans le bouquin

Par contre, tout à la fin, tu m'as tout perdu.

Alp a écrit:

Code:

getPlayerList (PlayerManager playerList) = playerList

wtf ?
Rassure-moi, ça n'a bien aucun rapport avec cette expression :

Code:

p@(Player {munitions = m, nom = n})

?
De quel droit tu peux écrire une fonction en argument ? (-> ah oui ça ok d'accord )
mais en gros cette fonction prend une fonction en paramètre et la retourne ? C'est l'identité quoi ?

oops je suis en retard :/
merci !!!


_________________________________________________________
Remember, raptors run at 10m/s and do not know fear.
http://membres.lycos.fr/Arnaud1602/CalvinhobbesLogo.gif

Hors ligne

 

#4 17-11-2009 15:47:38

Alp
Membre
Lieu: Marseille
Date d'inscription: 25-04-2006
Messages: 153
Site web

Re: idiomes de prog en Haskell

Non ce n'est psa une fonction en argument.
Quand tu as qqch comme PlayerManager là, tu as donc ton constructeur de valeur ("PlayerManager") qui te permet d'obtenir une valeur de type TPlayerManager. Hé bien, tout ce qu'on va faire, c'est définir la fonction getPlayerList avec tu pattern matching !
On va matcher un objet de type TPlayerManager sur (PlayerManager playerList) où justmement playerList est le nom qu'on donne à la liste, juste la liste de Player, la [Player] quoi, sans le "PlayerManager" devant.

C'est comme quand on définie une fonction comme ça :

Code:

f [] = 0
f (x:xs) = 1 + f xs

sauf que dans le cas de la liste on a 2 alternatives possibles, tandis que dans le cas du player manager on n'en a qu'une, car c'est forcément de la forme "PlayerManager uneListe".

Donc quelque part, c'est un peu la même idée qu'avec le @, mais pas tant que ça. Dans ton cas on donne juste un alias. Ici, on fait du pattern matching. C'est à dire qu'on "déconstruit" le TPlayerManager pour avoir d'une part "PlayerManager" et d'autre part la liste de Player.

Hors ligne

 

#5 17-11-2009 19:20:35

Wett
Administrateur
Date d'inscription: 10-04-2004
Messages: 2490

Re: idiomes de prog en Haskell

Hors-sujet:

C'est marrant mais... ça m'a pas donné envie du tout de me mettre au haskell !


...
Nyah.
<- avatar de www.haname.net.
http://imagegen.last.fm/pwetts/recenttracks/Pwett.gif

Hors ligne

 

#6 17-11-2009 19:43:09

Alp
Membre
Lieu: Marseille
Date d'inscription: 25-04-2006
Messages: 153
Site web

Re: idiomes de prog en Haskell

Rho la mauvaise langue ! Et puis laisse le, tu vois pas qu'il est à fond dedans là ? 006_grin C'est bien ! Ca apporte un recul considérable sur la programmation !

Dernière modification par Alp (17-11-2009 19:43:23)

Hors ligne

 

#7 17-11-2009 20:55:27

Calvin1602
Administrateur
Lieu: Rennes
Date d'inscription: 15-04-2005
Messages: 2262
Site web

Re: idiomes de prog en Haskell

Bon.

Je suis TRÈS énervé. Genre, TRÈS énervé.

J'en ai rien à foutre qu'un langage permette de faire des tas de trucs merveilleux en 2 lignes si on peut même pas AFFICHER UNE PUTAIN DE VARIABLE

Dans ma (courte, certes, mais quand même) vie j'ai fait de l'assembleur, du caml, du prolog, j'ai codé sur 4 plate-formes embarquées, et jamais, JAMAIS, j'ai été bloqué 2 jours consécutifs pour simplement AFFICHER DU TEXTE. Je veux bien admettre être borné, stupide, ne pas avoir suffisement RTFM et tout, mais quand même, MERDE, quoi.

RAAAAHHH

022_nuke

Je voulais tout connement mettre le print dans la fonction play. Genre, j'affiche le nouveau player que j'ai calculé.
Ça m'aurait permis de voir l'évolution de mon PlayerManager au fur et à mesure des appels à playall. Ben c'est impossible. Juste impossible. Ce connard de print retourne un IO, qu'il est tout simplement impossible d'ignorer, de jeter à la poubelle ou quoi. Autrement dit, je suis condamné à retourner ce IO ( au lieu de mon TPlayer que je voulais à la base ). Et qui plus est, je peux pas faire du séquenciel tellement c'est pur. Pire que tout, main attend du IO, lui, du coup je peux pas faire de main une simple fonction qui crée un playermanager et playall.
C'est peut-être pas impossible mais je suis tellement hors de moi que j'ai même pas envie de connaître la réponse.



Oh, et autre chose : Ya un F*CKING garbage collector !

!!!!!!!

Alp a écrit:

Et puis laisse le, tu vois pas qu'il est à fond dedans là ?

tkt, c'est bien retombé.


_________________________________________________________
Remember, raptors run at 10m/s and do not know fear.
http://membres.lycos.fr/Arnaud1602/CalvinhobbesLogo.gif

Hors ligne

 

#8 17-11-2009 21:18:18

Alp
Membre
Lieu: Marseille
Date d'inscription: 25-04-2006
Messages: 153
Site web

Re: idiomes de prog en Haskell

En Haskell t'as les monades. En particulier, toutes les entrées/sorties t'obligent à passer par IO. C'est super contraignant au début, mais très pratique par la suite. Ca sépare vraiment le code métier de tout ce qui est IO.

Si tu veux afficher les player, tu peux le faire par exemple dans main car elle retourne IO.

Mais de toute manière, je te conseille de (re)lire le chapitre sur les monades de RWH pour bien piger tout ça, et je crois même qu'il y a aussi tout un passage sur l'IO.

Après si t'as plus envie tant pis 006_grin

Hors ligne

 

#9 17-11-2009 23:46:05

Alp
Membre
Lieu: Marseille
Date d'inscription: 25-04-2006
Messages: 153
Site web

Re: idiomes de prog en Haskell

Mais sinon tu peux juste faire :

Code:

main = mapM_ putStrLn (map (show . play) playerList)

Le premier map va "jouer" chacun des player et les trasnformer en String (grâce au 'deriving (Show)') tandis que le second, mapM_, va faire un map dans la monade IO en ignorant le résultat (c'est ce que signifie le '_', tandis que le 'M' réfère à "Monad"). Donc il va prendre chacune des chaînes et les passer à putStrLn, sans mettre le résultat dans une liste (parce que c'est mapM_ et non mapM). Tu aurais aussi pu faire :

Code:

main = mapM_ (putStrLn . show) (map play playerList)

Hors ligne

 

#10 18-11-2009 09:14:10

Aquanum
Administrateur
Date d'inscription: 08-04-2004
Messages: 1991
Site web

Re: idiomes de prog en Haskell

Hors-sujet:

Je plussoie le Wett ! Le Haskell a l'air d'être pire que le VB (troll inside). Je suis très bien avec mon C :-)


Mon blog - Mes robots : Genesis - Robert

Hors ligne

 

#11 18-11-2009 11:53:59

nicolas66
Membre
Lieu: Région parisienne
Date d'inscription: 14-07-2006
Messages: 447
Site web

Re: idiomes de prog en Haskell

Hors-sujet:

Pire que le VB ... c'est possible ça ? :-)


Athlon 64 Dual Core 6000+ & GeForce 8600GT (Debian 5.0)

Hors ligne

 

#12 18-11-2009 12:23:30

Alp
Membre
Lieu: Marseille
Date d'inscription: 25-04-2006
Messages: 153
Site web

Re: idiomes de prog en Haskell

Hors-sujet:

Pire que le VB ? Faut pas abuser non plus 006_grin

Hors ligne

 

#13 18-11-2009 12:23:51

Funto
Administrateur
Lieu: Sendai, Japon
Date d'inscription: 11-04-2004
Messages: 3094
Site web

Re: idiomes de prog en Haskell

Hors-sujet:

Quelqu'un a écrit:

Dans ma (courte, certes, mais quand même) vie j'ai fait de l'assembleur, du caml, du prolog, j'ai codé sur 4 plate-formes embarquées, et jamais, JAMAIS, j'ai été bloqué 2 jours consécutifs pour simplement AFFICHER DU TEXTE

GOTOPRINTDUTEXTE()...

Hors ligne

 

#14 18-11-2009 17:34:52

nicolas66
Membre
Lieu: Région parisienne
Date d'inscription: 14-07-2006
Messages: 447
Site web

Re: idiomes de prog en Haskell

Hors-sujet:

Waou 2 jours là-dessus ? Qui dit mieux ?


Athlon 64 Dual Core 6000+ & GeForce 8600GT (Debian 5.0)

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr