42 votes

Core.async n'est-il pas contraire aux principes de Clojure ?

J'ai vu de nombreux programmeurs Clojure enthousiastes à propos de la nouvelle bibliothèque core.async et, bien qu'elle semble très intéressante, j'ai du mal à voir comment elle se conforme aux principes Clojure, c'est pourquoi j'ai ces questions :

  1. Il utilise l'état mutable partout, comme les noms des fonctions le suggèrent en ayant un point d'exclamation, comme alt !, put !, > !, et d'autres. Si vous mettez ou prenez une valeur d'un canal, ce canal est modifié sur place. N'est-ce pas contraire à la philosophie de Clojure qui préfère les structures de données immuables, les fonctions pures et ainsi de suite ? Ou est-ce que core.async est fait pour être utilisé uniquement lorsque les choses mutables ne peuvent pas être évitées du tout ?

  2. Étant donné que "go" est une macro (modifiant ainsi la structure du code) et qu'il garantit que "< !" est utilisé directement dans un bloc go, il n'est pas possible d'utiliser "< !" à l'intérieur d'une autre fonction, comme ceci :

    (defn take-and-print [c]
     (println (<! c)))
    
    (def ch (chan 1))
    (>!! ch 123)
    
    (go (take-and-print ch))
    
    Assert failed: <! used not in (go ...) block

    Il me semble que cela empêche la simplicité et la composabilité. Pourquoi cela ne pose-t-il pas de problème ?

  3. Peut-être en conséquence des deux problèmes précédents, beaucoup de code avec core.async utilise des constructions de plus bas niveau comme loop/recur au lieu de map/filter/reduce. N'est-ce pas un pas en arrière ?

Où est-ce que je rate le coche ?

Merci d'avance.

37voto

dnolen Points 12833

La première préoccupation - oui les opérations de base sont des effets secondaires. Cependant, les canaux n'ont pas les problèmes normalement associés aux références mutables car ils ne représentent pas un "lieu" - les canaux sont opaques, vous ne pouvez pas les inspecter, en fait vous ne pouvez même pas demander si un canal est fermé ou non au-delà de la lecture de nil.

La deuxième préoccupation - faire quelque chose de plus que le rendement superficiel signifierait une transformation complète du programme. C'est un compromis et je pense qu'il est raisonnable. Le niveau de composition est constitué de canaux et non de blocs et ils se composent très bien.

Enfin, vous pouvez facilement effectuer des opérations de map/filter/reduce de style Rx sur des canaux, et des personnes l'ont déjà fait.

16voto

cgrand Points 4922

La limitation de la macro go (sa localité) est également une caractéristique : elle permet de faire respecter la localité du code source pour les opérations avec état.

11voto

Arthur Ulfeldt Points 45059
  1. c'est un peu l'inverse, Core.async ne peut être utilisé que dans des systèmes où l'immutabilité est la norme. . Les principes de Clojure permettent donc à core.async plutôt que l'inverse.

  2. Il s'agit d'une limitation, qui se produit également à d'autres endroits dans clojure, la limitation des fonctions anonymes qui ne composent pas avec la fonction % Le symbole semble au moins présenter la même idée. Non pas que le fait de trouver un autre cas de limitation rende la situation meilleure, bien sûr.

  3. Je n'ai pas vu cela moi-même, mais ce serait un pas en arrière si vous essayiez de prendre un code qui est simple et propre lorsqu'il est exprimé d'une certaine manière et de l'exprimer d'une manière qui n'est pas cette manière...

5voto

claj Points 1723

Rich Hickey a dit dans l'une des conférences de blip.tv que Clojure est " 85 % fonctionnel ". J'aime voir core.async comme une partie des autres 15%. Core.async est excellent pour une interaction solide avec l'utilisateur, entre autres choses, ce qui aurait été fait par des promesses, des délais et d'autres choses, probablement d'une manière plus désordonnée.

2voto

nickik Points 3112

Chaque programme a deux parties, une partie qui est toujours non fonctionnelle : on entre les données, on les recrache et ainsi de suite. Pour cette partie, nous avons core.async, il est vrai que core.async a des choses mutables, mais notez deux choses. L'état des canaux est fondamentalement géré par la bibliothèque. Les choses que vous mettez dessus sont, ce qu'on pourrait appeler flowstate. Cela signifie que lorsque vous mettez quelque chose comme un canal, vous ne vous attendez pas à y revenir, ou même à le modifier.

Core.async permet de gérer cette partie de votre programme. Pour le reste, toutes les transformations et calculs sur vos données, clojure fait de son mieux pour vous donner de bons outils pour le faire fonctionnellement.

Il me semble que cela empêche la simplicité et la composabilité. Pourquoi n'est-ce ce n'est pas un problème ?

Il y a deux mondes, le monde synchrone et le monde asynchrone. Vous pouvez mettre des choses ou prendre des choses dans le monde asynchrone avec put ! et take ! mais à part cela (et peut-être quelques autres fonctions), ces deux mondes sont séparés l'un de l'autre. Clojure ne veut pas devenir un langage complètement asynchrone. Ce sont les fonctions et la transformation des données qui doivent être composables.

Peut-être en conséquence des deux problèmes précédents, beaucoup de code avec core.async utilise des constructions de plus bas niveau comme loop/recur au lieu de map/filtre/reduce. N'est-ce pas un pas en arrière

Il sera possible de fonctionner comme ça sur les canaux. Core.async est encore jeune et toutes les constructions et fonctions possibles n'ont pas encore été écrites.

Mais en général, si vous avez de grandes transformations de données, vous ne voulez pas vraiment les faire dans un monde asynchrone, vous voulez les avoir dans une collection et ensuite lancer quelque chose comme le framework reducres.

La principale chose à comprendre est la suivante : core.async n'est pas le nouveau standard, c'est juste une chose de plus qui vous aide à programmer. Parfois vous avez besoin de STM, parfois d'Agents, parfois de CSP, cela dépend et clojure veut vous donner toutes les options.

L'une des raisons pour lesquelles les gens apprécient core.async est qu'il permet de gérer certaines choses qui sont autrement très difficiles à gérer, comme le traitement des callbacks.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X