Journal Comprendre Go en 5 minutes, en Haskell

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
18
24
déc.
2019

D'après leur réputation, Go et Haskell sont des langages de programmation assez opposés : Go privilégie la simplicité, Haskell l'expressivité. Cependant ces deux langages ne sont pas si éloignés que cela. Plus exactement, les concepts de base de Go se retrouvent, de façon assez ressemblante, en Haskell.

Ce journal reprend, en Haskell, les exemples de code en Go de l'article Comprendre Go en 5 minutes. L'objectif n'est pas de présenter exhaustivement Go ou Haskell, ni de démontrer que l'un est "meilleur" que l'autre mais plutôt de montrer l'équivalent en Haskell de quelques fonctionnalités de Go.

Avertissement : je ne connais rien à Go et ne suis pas un expert en Haskell. Les exemples ci-dessous présentent juste ce que j'en ai compris.

Hello world

Commençons par le traditionnel "helloworld". En Go, il faut définir un package, importer le module fmt et définir une fonction main.

package main

import "fmt"

func main() {
    fmt.Println("hello world")
}

En Haskell, il faut également définir une fonction main mais il n'est pas nécessaire de définir un module ni d'importer de module particulier.

main :: IO ()
main = putStrLn "hello world"

Fonctions

En Go, la définition et l'évaluation de fonction ressemble à n'importe quel langage de type "langage C".

package main

import "fmt"

func add(x int, y int) int {    // définit une fonction add
    return x + y
}

func main() {
    var i, j int = 10, 2
    fmt.Println(add(i, j))    // évalue add
}

En Haskell, on utilise la forme curryfiée et sans parenthèse d'évaluation.

add :: Int -> Int -> Int    -- définit une fonction add
add x y = x + y

main :: IO ()
main = do
    let i = 10
        j = 2
    print (add i j)    -- évalue add

Interfaces

Go permet de définir des types et des interfaces. Par exemple, on peut définir un type GoDeveloper implémentant une interface Developer.

package main

import "fmt"

type Developer interface {    // définit une interface Developer
    Code() string
}

type GoDeveloper struct {    // définit un type GoDeveloper
}

func (g GoDeveloper ) Code() string {    // implémente Developer pour GoDeveloper
    return "Go code"
}

func main() {
    goDeveloper := GoDeveloper{}
    fmt.Println(goDeveloper.Code())
}

Le système de type de Haskell est très évolué mais les classes de types et les types algébriques permettent d'écrire un code équivalent au code Go précédent.

class Developer a where    -- définit une "interface" Developer
    code :: a -> String

data GoDeveloper = GoDeveloper    -- définit un type GoDeveloper

instance Developer GoDeveloper where    -- implémente Developer pour GoDeveloper
    code g = "go code"

main :: IO ()
main = do
    let goDeveloper = GoDeveloper
    putStrLn (code goDeveloper)

Processus légers

Enfin, Go propose des processus légers, appelés "go routines" et lancés via le mot-clé go.

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")    // lance un processus léger, en parallèle
    say("hello")
}

Haskell possède également des processus légers, lancés via forkIO.

import Control.Concurrent
import Control.Monad
import System.Clock

say :: String -> IO ()
say s = forM_ [1 .. 5] $ \_ -> do
    threadDelay 100000
    putStrLn s

main :: IO ()
main = do
    forkIO (say "world")    -- lance un processus léger, en parallèle
    say "hello"

Conclusion

Le langage Go permet de définir et d'utiliser des fonctions, des types, des interfaces et des processus légers (appelés "go routines"). Ces fonctionnalités existent également en Haskell et s'utilisent de façon assez ressemblante.

  • # Merci pour les explications !

    Posté par  (site web personnel) . Évalué à 4.

    Je pense que c'est un bon exemple pour montrer de la programmation fonctionnelle, voir le parallèle avec des technologies "modernes" et se rendre compte que c'était là depuis le début ! [musique dramatique]

  • # Haskell super expressif ?

    Posté par  . Évalué à 5.

    Quelqu'un pour donner plus de détails sur comment s'interprète la partie suivante ?

    add :: Int -> Int -> Int    -- définit une fonction add
    add x y = x + y

    Je veux bien que haskell soit "super expressif", mais la première ligne ne me parle pas du tout. Pourquoi des flèches sont-elles utilisées pour typer les variables de la fonction ? Une flèche implique une relation de cause à effet, ou une sorte de hiérarchie ; or rien de tel entre x et y, non ?

    A ce compte là, je préfère la version go (ou pratiquement n'importe quel autre langage) qui permet de savoir clairement quelle variable a quel type.

    • [^] # Re: Haskell super expressif ?

      Posté par  (site web personnel) . Évalué à 6.

      D'un point de vue pratique, on peut considérer ça comme un détail de syntaxe.

      D'un point de vue plus théorique, ça s'appelle la curryfication et c'est utilisable dans pas mal de langages. Ça consiste simplement à écrire une fonction à plusieurs paramètres sous la forme de fonctions à un paramètre qui retournent d'autres fonctions à un paramètre. Il y a une page wikipedia à ce sujet (https://fr.wikipedia.org/wiki/Curryfication) et un article+vidéo sur mon site perso (https://nokomprendo.gitlab.io/posts/tuto_fonctionnel_13/2018-02-25-README.html).

      • [^] # Re: Haskell super expressif ?

        Posté par  . Évalué à 4.

        Merci beaucoup pour cet éclairage.

        Par contre, pour moi ce n'est pas un détail de syntaxe. C'est plutôt un point d'implémentation qui vient impacter la syntaxe. Le point sous-jacent étant : est-ce que le développeur a besoin de savoir quelque chose à propos de la curryfication/décurryfication ?

        Dis autrement : je suis une quiche totale en programmation fonctionnelle, mais j'ai quand même tendance à penser que pour un être humain normal, la conception se fait en disant "j'ai x et y, deux entiers, qui servent à calculer un produit", donc une seule fonction, et pas un enchaînement de deux fonctions.

        Dis encore autrement : je vois que la curryfication permet d'avoir des fonctions pures (et je pense percevoir l'intérêt de celles-ci), mais je ne vois pas en quoi ça justifie de faire de la curryfication systématique, et encore moins de venir impacter la syntaxe avec cette notion. Le remède n'est-il pas pire que le mal ?

        • [^] # Re: Haskell super expressif ?

          Posté par  . Évalué à 4.

          Je ne comprends pas pourquoi les formes curryfiées seraient nécessaires pour avoir des fonctions pures. Une fonction de type A × B → C peut tout autant être pure que A → B → C.

          Pour moi, l'intérêt des fonctions curryfiées était avant tout l'application partielle.


          Pour la lecture, une fois qu'on me l'a expliqué, ça ne m'a jamais dérangé. Le prérequis important me semble de savoir dans quel ordre les flèches doivent être lues (elles ne sont pas associatives).
          A → B → C est A → (B → C) et non (A → B) → C. Le type du retour est donc derrière la dernière flèche, les autres flèches séparent les arguments dans l'ordre dans lequel on doit les donner. Si on veut retourner plusieurs objets, on est obligé d'utiliser un produit : A → B × C.

          • [^] # Re: Haskell super expressif ?

            Posté par  . Évalué à 2.

            Bah, j'ai toujours trouvé la curryfication assez nulle (je ne suis pas utilisateur d'Haskell):
            1) pourquoi l'application partielle doit être lié à l'ordre des éléments?

            Avec une syntaxe assez simple, il serait possible de faire la même chose: si _ est un argument a remplir plus tard, il est possible de faire f(x, _ , y).

            2) la plupart du temps les fonctions ont besoin de n arguments, et si tu en donne un nombre différents, c'est un bug, avec la curryfication c'est une application partielle, ça n'aide pas à trouver la source du bug.
            Certes l'application partielle, ça peut être sympa comme fonctionnalité OK, mais par défaut? Non merci.

            Par contre pour pouvoir gérer les fonctions avec un nombre variable d'éléments, j'aime bien l'idée d'une opérateur .. ou _* pour remplacer un ou plusieurs éléments a la fin.

            • [^] # Re: Haskell super expressif ?

              Posté par  (site web personnel) . Évalué à 2.

              Perso, je vois la chose dans l'autre sens : si on a les concepts de "fonction simple" et de "curryfication" alors on a gratuitement les fonctions à plusieurs paramètres et l'évaluation partielle.

              En pratique dans Haskell, l'évaluation partielle n'est ni une killer feature ni une véritable source d'erreur (le compilateur, voire le linter, détecte facilement ce genre d'erreur). Par contre, si on fait un peu attention quand on définit nos fonctions, ça permet de simplifier un peu le code pour très peu d'effort.

            • [^] # Re: Haskell super expressif ?

              Posté par  (site web personnel) . Évalué à 2.

              1) Les arguments nommés et ou à valeur par défaut me manquent terriblement en Haskell donc je suis d'accord avec toi ;)

              2) Ce ne sera pas un bug mais une erreur de type. Certes pas forcément toujours évidente et pouvant se propager un peu plus loin à cause de l'inférence de type. En pratique c'est rarement un problème dans mon expérience.

            • [^] # Re: Haskell super expressif ?

              Posté par  (site web personnel) . Évalué à 2. Dernière modification le 30 décembre 2019 à 16:07.

              Par contre pour pouvoir gérer les fonctions avec un nombre variable d'éléments, j'aime bien l'idée d'une opérateur .. ou _* pour remplacer un ou plusieurs éléments a la fin.

              Pour troller je te répondrais bien "sympa comme fonctionnalités mais par défaut pas OK". Cela peut générer son lot de bugs amusants aussi. En fait je n'ai jamais trop vu intérêt de cette fonctionnalité (et même après des décennies de python ;)

              • [^] # Re: Haskell super expressif ?

                Posté par  . Évalué à 2.

                Amusant car ce que je décris ici, il me semble que c'est l'équivalent de l'application partielle liée a la curryfication..

                • [^] # Re: Haskell super expressif ?

                  Posté par  (site web personnel) . Évalué à 2.

                  Ma citation était mauvaise, je voulais troller sur les fonctions avec un nombre variable d'argument.

                  Tu disais:

                  Par contre pour pouvoir gérer les fonctions avec un nombre variable d'éléments,

                  C'est sur cela que je répondais, pardon. Gérer des fonctions avec un nombre variable d'argument, je ne suis pas forcement fan.

                  Je n'ai rien contre ta proposition de f(x, _, z) représentant la création d'une fonction anonyme y -> f(x, y, z). J'avoue que je ne sais pas vraiment si c'est mieux ou moins bien et que je suis habitué à la version Haskell. On pourrait surement faire une comparaison poussée des différences entre les deux syntaxe, à un moment il faut faire un choix.

            • [^] # Re: Haskell super expressif ?

              Posté par  . Évalué à 1.

              En effet, l'intérêt est limité. Mais il faut aussi se poser la question dans l'autre sens : quels sont les désavantages des fonctions curryfiées et quels sont les avantages des fonctions prenant un tuple de tous les arguments en même temps ?

              J'en vois assez peu. Le principal, comme le montre l'existence de ce fil, c'est que ça perturbe ceux qui ne connaissent pas. Donc dans la plupart des langages, les fonctions curryfiées sont à éviter sauf quand c'est vraiment utile. Mais dans les langages dans lesquels c'est idiomatique (comme le Haskell ou d'autres langages fonctionnels), ça ne coûte rien de curryfier par défaut et de n'utiliser les tuples seulement quand c'est vraiment nécessaire.

              Je rappelle aussi qu'en maths, une fonction associe à chaque élément d'un domaine un élément du codomaine. Si on veut passer plusieurs paramètres, le domaine est un ensemble produit et on doit créer un tuple pour passer les paramètres. Dans beaucoup de langages ce n'est pas un problème, mais j'imagine que pour un langage très matheux comme Haskell c'est une source de complexité supplémentaire (en pratique on devra écrire add (a,b) au lieu de add a b, c'est un peu plus lourd mais ça reste acceptable, la principale raison reste idiomatique).

              Avec une syntaxe assez simple, il serait possible de faire la même chose: si _ est un argument a remplir plus tard, il est possible de faire f(x, _ , y).

              Il y a des langages qui proposent ce genre de syntaxe ? Est-ce que c'est vraiment plus clair qu'une syntaxe du genre z => f(x, z, y).

              • [^] # Re: Haskell super expressif ?

                Posté par  . Évalué à 2.

                quels sont les désavantages des fonctions curryfiées et quels sont les avantages des fonctions prenant un tuple de tous les arguments en même temps ?
                J'en vois assez peu.

                On s'habitue à tout (je suis tellement habitué au C qu'il m'a fallu un certain temps pour réaliser/admettre que sa syntaxe de déclaration des variables est une hérésie)..
                Mais j'avais dit plus haut:
                1) la vérification que l'appel a le bon nombre d'argument est retardée.
                Je persiste a le penser et j'ajouterai:
                2) la lisibilité si tu as fn f: a b -> c, tu vois tout de suite que tu a et b comme entrée et c comme retour, si tu as fn f: a -> b -> c, c'est moins immédiat.

                Pour les avantages: moi j'en vois assez peu, mis à part des pseudo-justifications mathématiques, la souplesse liée a l'application partielle peut être mieux faite avec une syntaxe simple (le _).

                • [^] # Re: Haskell super expressif ?

                  Posté par  (Mastodon) . Évalué à 2.

                  je suis tellement habitué au C qu'il m'a fallu un certain temps pour réaliser/admettre que sa syntaxe de déclaration des variables est une hérésie

                  Pourrais-tu préciser ta pensée ?

                  • [^] # Re: Haskell super expressif ?

                    Posté par  . Évalué à 4.

                    La syntaxe de déclaration du C n'est ni-prefix, ni-postfix..
                    var a: [10]int; peut se lire facilement de gauche a droite a est un tableau de 10 éléments entiers.
                    int[10] a; tout aussi simple a lire, même si on aurait tendance a le lire de droite a gauche.

                    Mais int a[10]; là c'est le bazar.. Je me souviens d'un manuel du C qui disait qu'il fallait lire "en spirale" les déclarations, simple!
                    Il y a le classique int *a, b; aussi qui montre bien le problème: a est un pointeur pas b.
                    Résultat: les guides de codages déconseille de déclarer plusieurs variables en même temps..

                    Il y a plein de langages qui essayent d’améliorer le C (spécialement: les conversions implicites, les comportements indéfinis, la priorité des opérateurs..) et la plupart du temps ils ne résistent pas à la tentation de corriger la syntaxe de déclaration des variables..

                • [^] # Re: Haskell super expressif ?

                  Posté par  (site web personnel) . Évalué à 2. Dernière modification le 31 décembre 2019 à 18:05.

                  la vérification que l'appel a le bon nombre d'argument est retardée.

                  J'ai déjà avoué dans un autre commentaire que cela pouvait générer des erreurs de type parfois étonnantes, mais je répète que dans mon expérience cela ne m'a jamais dérangé. Cependant mon expérience se limite à Haskell et donc j'ai du mal à voir ce que cela peut donner dans un autre langage.

                  la lisibilité si tu as fn f: a b -> c, tu vois tout de suite que tu a et b comme entrée et c comme retour, si tu as fn f: a -> b -> c, c'est moins immédiat.

                  L'application partielle biaise notre façon de développer des interfaces, on s'habitue très vite à voir f comme plusieurs possibilités, celle qui te semble immédiate (2 arguments, un retour qui n'est pas une fonction), et l'autre (un argument, un retour qui est une fonction).

                  Après si vraiment tout cela t’embêtes et que c'est la seule chose qui te bloque en Haskell, tu peux faire des fonctions qui prennent des tuples, ainsi fn aura comme type (a, b) -> c et son appel se fera avec un tuple: fn (a, b). La vérification sera faite "au bon endroit", la syntaxe de déclaration de fonction va ressembler à quelque chose que tu connais et tout sera bien et chaque fois que tu auras besoin d'une fonction appliquée partiellement, tu pourras faire une lambda: \x -> fn(a, x) ;)

        • [^] # Re: Haskell super expressif ?

          Posté par  . Évalué à 1.

          Le point sous-jacent étant : est-ce que le développeur a besoin de savoir quelque chose à propos de la curryfication/décurryfication ?

          Oui c'est extrêmement pratique dans un paquet de situation. Par exemple à chaque fois que tu as une série de boucles imbriquées. Le code de la boucle la plus profonde est une fonction prenant en paramètre l'ensemble des éléments courants de chaque boucle.

          La décurryfication n'existe pas.

          Après je présume qu'avec les mots clefs haskell et curryfication, tu aura tôt fait d'invoquer un habitué du site qui se fera un plaisir de te faire un cours magistral sur la question (tout en laissant passer un ou 2 trolls sur l'orienté objet).

          https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

          • [^] # Re: Haskell super expressif ?

            Posté par  (site web personnel) . Évalué à 2.

            La décurryfication n'existe pas.

            curry et uncurry ;)

            Je compléterais en disant que la curryfication est vraiment un élément de design. Sans tomber dans le "troll" sur l'orienté objet, il est tout à fait possible d'avoir de la curryfication dans un context "orienté objet". On peut tout faire sans, mais des fois cela simplifie un peu. Je vivrais très bien en Haskell sans cette fonctionnalité, mais c'est souvent pratique.

            • [^] # Re: Haskell super expressif ?

              Posté par  . Évalué à 1.

              Je pensais à un autre amoureux du paradigme fonctionnel mais aussi de philosophie (explique lui que Kant n'est pas parfait et il t'en coûtera) qui a su mal à ne pas glisser dans ses longues explications que l'orienté objet est fondamentalement défaillant.

              https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

    • [^] # Re: Haskell super expressif ?

      Posté par  . Évalué à 5. Dernière modification le 26 décembre 2019 à 18:35.

      La même chose existe en Javascript, si ça peut t’aider :

      const add = a => b => a + b;
      const increment = add(1);
      const ten = increment(9);
      const twenty = add(ten)(10);
      • [^] # Re: Haskell super expressif ?

        Posté par  (site web personnel) . Évalué à 4.

        Exact.

        Et aussi en python :

        add = lambda x: lambda y: x+y

        Et aussi en C++ :

        auto add = [](int x) { return [x](int y) { return x+y; }; };

        Et dans tous les langages qui peuvent manipuler des fonctions comme objet de première classe (https://fr.wikipedia.org/wiki/Objet_de_premi%C3%A8re_classe).

        • [^] # Re: Haskell super expressif ?

          Posté par  . Évalué à 1.

          Et en Go

          package main
          
          func main() {
              var add = func(a int) func(b int) int {
                  return func(b int) int {
                      return a + b
                  }
              }
          
              var x = 1
              var y = 2
              println(add(x)(y))
          
          }

          À noter qu'il y a un builtin println qui permet d'afficher sans importer le package fmt.
          Après, le fmt.Println est bien plus avancé (affiche et met en forme tous les type de Go, prends des paramètres variadique, etc)

    • [^] # Re: Haskell super expressif ?

      Posté par  (site web personnel) . Évalué à 2. Dernière modification le 29 décembre 2019 à 10:54.

      Si vraiment tu veux mettre le type sur chaque variable, tu peux:

      add (x :: Int) (y :: Int) = x + y
      (Cela demande l'extension ScopedTypeVariables)

      Si tu y tient aussi, tu peux tout écrire avec des tuples:

      add' (x :: Int, y :: Int) = x + y
      C'est là que curry et uncurry interviennent:

      Prelude> :t add
      add :: Int -> Int -> Int
      Prelude> :t add'
      add' :: (Int, Int) -> Int
      Prelude> :t curry add'
      curry add' :: Int -> Int -> Int
      Prelude> :t uncurry (curry add')
      uncurry (curry add') :: (Int, Int) -> Int
      Prelude> :t uncurry add
      uncurry add :: (Int, Int) -> Int
      Prelude> :t curry (uncurry add)
      curry (uncurry add) :: Int -> Int -> Int
      Trouve le style qui te convient ;)

      Maintenant tu demandes :

      Une flèche implique une relation de cause à effet, ou une sorte de hiérarchie ; or rien de tel entre x et y, non ?

      En fait si. On va disuter un peu plus théorie pour s'amuser. Ce n'est ABSOLUMENT pas utile pour faire du Haskell. La https://fr.wikipedia.org/wiki/Correspondance_de_Curry-Howard établit une relation entre type / implémentation et théorème / preuve. Dit autrement, un type est un théorème et son implémentation une preuve.

      Reprenons l'exemple de add :: Int -> Int -> Int. C'est un théorème qui dit "Pour tout Int, pour tout autre Int, alors je peux associer un Int". Et la preuve est une preuve par construction avec la fonction + qui associe un Int à tout couple de deux Int.

      Dans le cas précis cela ne sert à rien. D'autant que ce n'est pas tout à fait vrai en Haskell car on peut faire des fonctions non totales (i.e. qui ne marchent pas pour toutes leurs valeurs). Mais cela devient très amusant de lire des signatures de cette manière.

      Un autre exemple: Int -> String est une fonction qui "à tout Int, associe une String". La preuve c'est la fonction de conversion vers string.

      • [^] # Re: Haskell super expressif ?

        Posté par  (site web personnel) . Évalué à 2.

        Yes. C'est beau.

        Pour les fonctions totales, je crois que Idris apporte quelques fonctionnalités intéressantes. Mais il faudra peut-être plus de 5 minutes pour comprendre le langage…

      • [^] # Re: Haskell super expressif ?

        Posté par  (site web personnel) . Évalué à 2.

        Je m'auto répound pour ajouter un truc. La déclaration de fonction en Haskell fait du "pattern matching" en même temps. La plupart du temps on ne pas pas utiliser des variables "simples", mais un "pattern".

        Exemple, pour faire une somme (il y a plus simple pour faire une somme, comme la fonction sum, c'est juste pour l'exemple).

        mySum :: [Int] -> Int
        mySum [] = 0
        mySum (x:xs) = x + mySum xs
        Ici on commence par le type [Int] -> Int. Puis vient l'implementation. Premier cas, la somme d'une liste vide [] qui vaut 0. Second cas, la somme d'une liste qui contient un élément x et une suite de liste xs.

        En utilisant la syntaxe "go", c'est à dire ou les variables ont leur type directement collé, cela donnerait un truc du genre:

        mySum ([] :: [Int]) = 0
        mySum (((x :: Int) : (xs :: [Int])) :: [Int]) = x + mySum xs
        Aucune de ces annotation de type n'est nécessaire ceci dit.

      • [^] # Re: Haskell super expressif ?

        Posté par  . Évalué à 2.

        Dans…

        Reprenons l'exemple de add :: Int -> Int -> Int. C'est un théorème qui dit "Pour tout Int, pour tout autre Int, alors je peux associer un Int". Et la preuve est une preuve par construction avec la fonction + qui associe un Int à tout couple de deux Int.

        …je ne vois toujours pas de relation hiérarchique (ou d'ordre) entre les deux premiers Int. Et donc, je continue à trouver cette syntaxe déroutante/inadaptée. Et j'ai tendance à penser que ce genre de choix, même si il peut trouver une justification dans les mathématiques classiques (que je ne vois pas pour le moment), est une bonne manière de tuer l'adoption d'un langage.

        • [^] # Re: Haskell super expressif ?

          Posté par  (site web personnel) . Évalué à 3.

          L'adoption du langage m'importe peu, surtout si pour des raisons que je considère futiles. C'est le même débat que l'indentation significative en python ;)

          Personnellement je trouve que cette syntaxe a -> b -> c représente bien mieux les deux possibilités f(a) -> (b -> c) ou f(a, b) -> c qu'une autre syntaxe et je trouve que c'est une très bonne manière de faire comprendre ce concept et d'amener à l'utilisation d'application partielle. Mais au final on s'en fout ;)

        • [^] # Re: Haskell super expressif ?

          Posté par  . Évalué à 1.

          …je ne vois toujours pas de relation hiérarchique (ou d'ordre) entre les deux premiers Int.

          Tu as pourtant déjà ce problème d'ordre dans l'énorme majorité des autres langages. Qu'est-ce qui te pousse à écrire f(a, b) au lieu de f(b, a) ? Mis a par nommant toujours tous les paramètres cet ordre figé tu l'a tout le temps et le monde ne s'écroule pas pour autant.

          C'est globalement le genre de critique où il faut vraiment prendre un peu de temps pour essayer plutôt que d'imaginer des problèmes qui ne sont peut être que potentiels.

          Si on te demande comment tu fais pour écrire du python sans curryfication, tu va répondre que dans la pratique ça ne pose pas de problème.
          Si tu demande comment on peut faire pour écrire de l'haskell avec des paramètres ordonnés, on va répondre que dans la pratique ça ne pose pas de problème.

          https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

          • [^] # Re: Haskell super expressif ?

            Posté par  . Évalué à 2.

            Alors d'abord, pour moi le principal challenge n'est jamais d'écrire le code, mais de le lire, ou de le faire lire par d'autres êtres humains, et de le rendre compréhensible le plus rapidement possible, sans ambiguité, pour faciliter sa maintenance/évolution.

            Et le fait qu'une syntaxe difficile à lire soit disponible me pose un vrai problème car il y aura toujours quelqu'un pour l'utiliser, et quelqu'un pour mal l'interpréter, ou plein de personnes pour perdre du temps à tenter de comprendre le comment et le pourquoi de la chose.

            Le développement logiciel, au-delà des concepts mathématiques, c'est une activité avant tout humaine, qui doit prendre en compte les biais humains et ne surtout pas les ignorer. Je ne suis pas un gros fan de Python, mais la philosophie générale du langage est bien dans cet esprit, et ça me plaît.

            • [^] # Re: Haskell super expressif ?

              Posté par  . Évalué à 1.

              J'ai parlé d'écrire mais c'est un biais dans ma façon de parler.

              Tu ordonne déjà tes paramètres et tu arrive à le lire dans n'importe quel langage sans que ça ai l'air de te poser tant de problème que ça.

              La lecture d'un code n'est en rien universelle. Là tu la juge avec ta subjectivité qui est fortement liée à ton habitude de lire d'autres syntaxe. C'est pour ça qu'il vaut mieux pratiquer plutôt que de tenter d'imaginer à partir de 3 bouts de code.

              Si non je pourrais très bien dire que « 안녕 세상 » est absolument illisible alors que le coréen est réputé par les linguistes comme étant très facile à apprendre/lire/écrire (entre autre, sa grammaire est totalement régulière).

              https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

  • # Question(s ?)

    Posté par  . Évalué à 1.

    Dans la partie implémentation d'interface, pourquoi sur Haskell, la fonction code n'affiche pas "go code" directement ? et à la place retourne la chaine "go code" ?
    Pour garder la fonction pure et ne pas avoir d'effet de bord (c'est lié aux monades ?)

    • [^] # Re: Question(s ?)

      Posté par  (site web personnel) . Évalué à 2.

      En fait, c'est tout simplement pour faire comme le code Go.
      Mais effectivement, même sans cela, c'est certainement ce qu'on aurait fait dans un code Haskell classique. Et effectivement, afficher directement demanderait de changer l'interface pour être dans la monade IO.

      class Developer a where
          code :: a -> IO ()
      
      data GoDeveloper = GoDeveloper
      
      instance Developer GoDeveloper where
          code _ = putStrLn "go code"
      
      main :: IO ()
      main = do
          let goDeveloper = GoDeveloper
          code goDeveloper

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.