• [^] # Re: Solution à base de types variants en ADA

    Posté par (site web personnel) . En réponse à la dépêche Sortie de GHC 8.0.2 et une petite histoire de typage statique. Évalué à 5.

    Oups, désolé, je ne sais plus comment on a réussi à dériver d'une discussion qui par du compilateur Haskell pour finir par parler des langages objets. Toute mes excuses pour des propos qui auraient pu être interprétés comme blasphématoires dans ce fil de discussion de conviction plutôt fonctionnelle.

    Aucune conviction ici, je ne sais toujours pas définir le fonctionnelle du "objet". Quand je présente Haskell, je ne parle pas d'un langage fonctionnel, parce que je ne sais toujours pas ce que cela veut dire. Même chose quand je parle de python.

    Souvent les débats "fonctionel" versus "object" tournent autour de conneries sans nom à mon humble avis. J'entend souvent que python n'est pas objet parce que il y a le self explicite en premier argument ? C n'est pas objet parce qu'il n'y a pas de classes ? Haskell n'est pas objet parce qu'il y a des classes mais qu'elle n'ont rien à voir avec les classes en C++. Pour moi l'objet c'est avoir des "trucs" qui représentent des "bidules" métiers et pouvoir faire passer des "messages" entres les "trucs". En C++ on parlera de "méthodes" ou "fonctions membres" pour faire passer les messages, en Haskell on parlera de "fonctions". L'objet pousse aussi l'encapsulation, qui sera effectuée en C++ par le bias de public / private et en Haskell par le biais d'un module qui export une liste définie de fonction. Au final on exprime la même chose. Comparons le code haskell suivant permettant de définir un type Poulet :

    module Poulet
     (Poulet, -- Export le type `Poulet`, mais pas son constructeur, on ne peut pas crée de poulet avec un age arbitraire, on ne peut pas non plus dépacker un poulet en dehors de ce module pour changer son nom ou son age
     cotcotcot, newPoulet, pouletAnniversaire)
    where
    data Poulet = Poulet Int String
    -- | La fonction cot cot cot
    -- fait faire cot au poulet autant de fois que son age.
    -- Un poulet de 3 ans fera "cotcotcot"
    cotcotcot :: Poulet -> String
    cotcotcot (Poulet age _) = concat (replicate age "cot")
    -- | Un poulet tout neuf, d'age 0, avec un nom de poulet
    newPoulet :: String -> Poulet
    newPoulet s = Poulet 0 s
    pouletAnniversaire :: Poulet -> Poulet
    pouletAnniversaire (Poulet age name) = Poulet (age + 1) name

    Voici la version C++ :

    class Poulet
    {
    private:
     int age;
     std::string name;
    public:
     explicit Poulet(std::string newName):age(0), name(newName)
     {}
     std::string cotcotcot() const
     {
     std::string ret;
     for(int i = 0; i < age; ++i)
     {
     ret += "cot";
     }
     return ret;
     }
     void anniversaire()
     {
     age++;
     }
    };

    La seule différence ici c'est que pour la version Haskell j'ai fais le choix de faire un type non mutable et de renvoyer un nouveau Poulet lors de son anniversaire. La version C++ modifie le poulet en place. Note que on pourrait bien faire l'inverse cela ne poserait aucun problème à aucun des deux langages, c'est juste que Haskell est plus partisan de données non mutable alors que C++ est plus partisan des donnée mutable, mais c'est juste une orientation que donne le langage, rien d'obligatoire.

    Bref, au final les différences entre les différents langages sont autres, par exemple, la présence ou non de pattern matching, que tu pourras trouver dans un langage objet ou dans un langage fonctionnel. Est-ce que le langage est plutôt orienté non mutable, ou mutable...

    Le reste c'est juste des noms à la con mis sur des concepts mal défini. Je me rappel un étudiant qui dans un examen devait résoudre un problème en utilisant la programmation dynamique. Il m'a écrit :

    Je ne sais pas ce qu'et la programmation dynamique parce que je ne suis pas venu en cours, mais je peux quand même résoudre votre problème avec une bonne complexité en utilisant un cache de résultat intermedaire, bla bla bla.

    Sans le savoir, il avait fait de la programmation dynamique.

    Tu ne sais pas ce qu'est un Functor, pas grave, tu l'a déjà utilisé sans le savoir. Pareil pour les Monad, Applicatives. Les opérateurs paresseux aussi. Le design pattern "visitor", c'est grosso modo du pattern matching.

    Désolé pour ce petit coup de gueule ;)