• [^] # Re: Fibo

    Posté par (site web personnel) . En réponse à la dépêche Sortie du Glorious Haskell Compiler 7.8. Évalué à 7.

    J'aurais du écrire "j'invite tout le monde" au lieu de "je vous invite", ce n'était pas du vouvoiement ;)

    Pour la syntaxe de l'exemple utilisant la mémoire transactionnelle, c'est la façon dont on écrit du code "impératif" en Haskell avec la do-notation. Donc ça se lit comme on lirait du C ou autre :

    -- On définit une fonction `transfertPognon` qui prend 3 paramètres (a,b,somme). Les types sont inférés.
    -- `atomically` permet d'exécuter ce qui lui est passé en paramètre dans une transaction. On ne peut pas faire d'IO dans une transaction donc elle est forcément pure (donc on peut la rejouer, etc.). Quand on accède aux variables transactionnelles, les écritures sont invisibles de l'extérieur tant que la transaction n'est pas "validée" ('commit').
    transfertPognon a b somme = atomically $ do 
     -- on lit la valeur stockée dans "a" qui est une variable de type `TVar Int` (donc qui ne peut être lue et écrite qu'avec readTVar et writeTVar respectivement au sein d'une transaction) et on l'affecte à `courantA`
     courantA <- readTVar a
     -- si le compte a n'a pas suffisamment d'argent, on appelle `retry`, ce qui aura pour effet de recommencer la transaction au début (donc de relire la valeur de `a`). Pour éviter de tourner pour rien comme sur un spinlock, le thread est bloqué jusqu'à ce qu'une des valeurs lues ait été modifiée (donc ici `a` vu qu'on a lu que cette variable). Pour rappel, les threads haskell sont des threads en espace utilisateur (green threads) donc ça ne coûte pas très cher.
     when (courantA < somme) retry 
     -- on lit `b` puis on écrit les 2 nouveaux montants dans les comptes
     courantB <- readTVar b 
     writeTVar a (courantA - somme) 
     writeTVar b (courantB + somme)

    Pour montrer comment on peut composer des fonctions qui utilisent la mémoire transactionnelle, on peut introduire deux fonctions retirer et verser pour enlever ou ajouter de l'argent à un compte donné :

    retirer compte somme = do
     courant <- readTVar compte
     when (courant < somme) retry
     writeTVar compte (courant - somme)
    verser compte somme = do
     courant <- readTVar compte
     writeTVar compte (courant + somme)
    transferer source dest somme = do
     retirer source somme
     verser dest somme
    transfertPognon a b somme = atomically (transferer a b somme)