Langage fonctionnel

Zeste de fonctionnel

a marqué ce sujet comme résolu.

Le contre-balancement de ça, c'est que l'extension de ce genre de types entraîne souvent la modification de code existant (les matching des fonctions qui traitent ce type), qui peuvent progressivement donner un nombre excessif de chemin d'exécution au sein de ces fonctions (augmentation des risques d'erreurs, difficulté de lecture, etc), et un grossissement assez méchant des fichiers qui contiennent ces fonctions du coup. Là où en objet, l'extension de type sera un nouveau comportement créé par héritage et isolé des comportements déjà présents (Open-Closed Principle).

Ksass`Peuk

OCaml intègre depuis la 4.02.0 l'extension d'un type algébrique qui était déjà présente avec le type exception notamment.

Maintenant, que le compilateur te signale que si tu changes un type algébrique, il faut changer tout le code qui en dépends est, selon mon expérience, un bienfait qu'une contrainte.

L'isolation d'extensions d'une AST (qui s'apparente forcément à des extensions du langage) en omettant arbitrairement ses dépendances (puisque tu parles d'isolation) permet juste de te tirer une balle dans le pied car tu casses la cohérence d'un pan de tes règles sémantiques dans ton langage. Et c'est pour cette raison qu'OCaml et Haskell auront toujours de l'avance dans ce domaine d'application par rapport à tout les autres langages - ils sont fait pour vérifier l'homogénéité de se qui reste être de la transformation d'un type à un autre et donc assure non seulement l'exhaustivité du traitement et la cohérence en interdisant le patch hack et l'ajout brutal d'informations sans prendre en compte l'ensemble.

Concernant la multitude de branchement conditionnel, si tu regardes bien le travaille qui a été fait sur le pattern matching et son optimisation et si tu regardes la sémantique du C++ et sa compilation, il est raisonnable de dire qu'OCaml ou Haskell (je ne sais pas trop ce dernier ne sachant pas comment il compile réellement le pattern matching) serait plus rapide sur ce point pour une seule raison, il n'est pas possible de faire du polymorphique ad-hoc (le simple fait que tu mettes les visiteurs en virtual plombe la vitesse puisque la décision est calculé au runtime avec la vtable, non plus par le compilateur) qui facilite le travail de décision du compilateur. En somme, il y aurait au temps de branchement conditionnel en C++ qu'en OCaml (dans le meilleur des cas), la seule différence c'est que l'un est déporter de manière implicite sur son modèle objet, tandis que l'autre est déporter de manière implicite sur son pattern-matching.

Enfin l'aspect objet et l'héritage dans ce genre de conception n'est pas un bienfait selon moi. Dans ce domaine, on assure que les éléments qui forment le langage sont définis de manière atomique et une extension de son comportement reviendrait souvent à être du sucre syntaxique si on parle de non-dépendance ou a une désambiguïsation des règles sémantiques qui nous amène souvent à re-atomiser l'élément en question (ce qui permet alors d'assurer l'application de manière exhaustive à nos nouvelles règles sémantique). Si on évite cette aspect là, on se retrouve alors avec un traitement in-décisionnel puisqu'il est humain d'oublier certains détails dans la conception - et c'est là où la contrainte qu'amène un compilateur comme celui d'OCaml devient intéressante.

Maintenant, que le compilateur te signale que si tu changes un type algébrique, il faut changer tout le code qui en dépends est, selon mon expérience, un bienfait qu'une contrainte.

Dinosaure

Qu'il te le signale c'est super, ça je ne dis pas le contraire. Le problème c'est le mot "changer" à mon sens. Quand on a du code qu'on a validé, introduire des changements c'est pas cool, parce que c'est autant de chances d'introduire des bugs dans du code qui fonctionnait.

Je suis pas sûr de comprendre ton paragraphe suivant. Si tu fais une extension à un type donné en objet, cette extension doit toujours respecter le contrat du type de base (LSP), on peut assez facilement mettre des gardes fous à ce niveau pour vérifier la préservation des invariants de classe. Tu n'as donc pas plus de chances de briser ta sémantique.

Concernant les performances du pattern matching, c'est juste un déplacement du problème. Si le type de ton sous arbre est connu à la compilation pas de raison de taper une résolution de type à l'exécution. Si le type de ton sous arbre est générique à la compilation dans un cas, c'est le matching qui fait le choix de dispatch à l'exécution, dans l'autre c'est la résolution de la vtable. A ce niveau c'est kif-kif par contre le matching permettra de jouer plus finement avec les caractéristiques du sous arbre plus tôt, et c'est là que les les gains vont apparaître.

Pour le dernier point je suis complètement d'accord. C'est ce que j'ai déjà dit, si ta structure est sujette à un multiple-dispatch, le choix du type algébrique est le meilleur plutôt que les visiteurs tordus qu'on écrit en objet (et c'est ce que pointe justement la vidéo dont j'ai parlé plus tôt).

Banni

Je lis en diagonale, mais concernant l'« expression problem », n'est-ce pas plutôt lié au fait que l'on considère un type somme ou un type qui implémente une certaine interface (par exemple les classes en Haskell et les modules en OCaml) plutôt que « fonctionnel » versus POO ? (je dis ça mais je n'ai jamais réussi à comprendre l'orienté objet)

@Idéophage : de mon point de vue c'est plutôt l'extension de type des deux philosophie qui est comparé, mais peut être parce que je n'ai pas fait assez de fonctionnel.

(je dis ça mais je n'ai jamais réussi à comprendre l'orienté objet)

Idéophage

Rien de bien compliqué, les objets sont des fournisseurs de services. On veut pouvoir fournir le même service de différentes manières et que ce soit transparent à l'usage.

Je lis en diagonale, mais concernant l'« expression problem », n'est-ce pas plutôt lié au fait que l'on considère un type somme ou un type qui implémente une certaine interface (par exemple les classes en Haskell et les modules en OCaml) plutôt que « fonctionnel » versus POO ? (je dis ça mais je n'ai jamais réussi à comprendre l'orienté objet)

Idéophage

Si bien sûr. C'est la comparaison entre type somme et type produit. Dans les langages raisonnables, sommes et produits sont traités équitablement - il se trouve que ces langages sont souvent fonctionnels, mais comme je le disais plus haut ça n'est pas une vraie raison. Dans la plupart des langages OO, les sommes sont très mal traitées (cc instanceof), d'où le fait que les gens aient retenu une opposition "fonctionnels vs objets".

+0 -0

Si bien sûr. C'est la comparaison entre type somme et type produit.

katana

Tu n'es pas en train de dire que "classe sensiblement équivalent à enregistrement" rassure moi.

Personnellement que je vois un instanceof en Java, j'ai la même chose qui me passe par la tête que quand je vois un dynamic_cast. Je me dis qu'il y a une erreur de conception quelque part. Si j'ai besoin de connaître le type d'un élément à un endroit où il est d'un type générique, c'est que j'ai merdé.

Non. A moins que tu puisses mettre deux modules, qui rendent le même service de manière différente, dans la même liste, sans boxing.

Dans chaque paradigme, il y a des concepts qui sont plus ou moins équivalents ou du moins servent les mêmes usages, mais dont la sémantique est très légèrement différente à chaque fois. Et leur usage est justement plus ou moins pratique selon la situation (c'est le principal endroit où les paradigmes se différencient les uns des autres).

  1. Du LISP en 94 (IIRC) dans une formation d'ingé info/math applis
  2. Je n'en utilise pas. Sauf si on considère que la meta-prog template en C++ c'est en partie du fonctionnel, et qu'il y a des bouts de fonctionnel en Python/Ruby.
  3. C++ ? Pro. Je suis passé à d'autres choses côté loisir.
  4. Plutôt procédural (et +)
  5. C++ et VimL principalement (et un peu d'xslt) – le reste est tombé en désuétude (côté "je m'en sers")
  6. Définitivement. Et un OO (qu'il soit procédural ou fonctionnel (CLOS)), et un déclaratif (Prolog ou XSLT), etc … Il est important d'avoir une certaine culture en dév, même si on n'utilise pas tout tout le temps.

Non. A moins que tu puisses mettre deux modules, qui rendent le même service de manière différente, dans la même liste, sans boxing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
module type S = sig
  type t
  val example : t
  val length : t -> int
end

module A : S = struct
  type t = int list
  let example = [1; 2; 3]
  let length = List.length
end

module B : S = struct
  type t = string array
  let example = [|"hello"; "world"|]
  let length = Array.length
end

let s_list : (module S) list = [(module A); (module B)]

Mais en dehors de ça, ce que je voulais souligner, c'est que ce qui est promis par la plupart des langages mainstream pour vendre les objets, à savoir « c'est un fournisseur de services, on peut changer l'implémentation, et l'interface est indépendante » se retrouve en fait, dans l'écrasante majorité des cas, de façon plus claire et mieux conçue dans les systèmes de modules comme on en a en OCaml. Et c'est d'ailleurs pour ça que les objets y sont très peu utilisés : ils ont leurs fonctionnalités propres (et difficilement remplaçables quand on en a besoin), mais ce que veulent la plupart des gens, c'est des modules.

+0 -0

J'ai du demander à un collègue de me l'expliquer celui là parce que je panais pas tout :lol: . La création de base est pratique et simple, l'usage un peu moins (let module S = (val v : S) ...).

Après sur le point "telle et telle notion se retrouve dans les autres paradigmes", oui je suis complètement d'accord, ce qui change c'est ce qui est implicite et explicite à l'écriture.

J'en profite pour faire une compilation des stats dans le post principal.


Je crois que tu connais bien Java si je me souviens bien. Du coup, une piste de transition "souple" vers le fonctionnel pourrait être Scala.

Javier

Bien vu ;) mais suite au sondage je devrais peut-être m'orienter vers quelque chose de plus mainstream comme OCaml.

+0 -0

mais suite au sondage je devrais peut-être m'orienter vers quelque chose de plus mainstream comme OCaml.

Ca serait intéressant de voir si OCAML est véritablement le langage fonctionnel le plus mainstream dans la vraie vie ou bien si ce n'est pas simplement dû à l'établissement dans lequel on étudie / a étudié.

JE dis ça parce que dans mon cas, j'ai été dans deux écoles, l'une était sur haskell et l'autre à fond sur scala. Personne n'a jamais mentionné même l'existence d'OCAML.

Question à poser donc à ceux qui font du fonctionel professionellement. Question bonus, en toute nautralité, pourquoi c'est ce langage-là qui aurait pris le dessus et pas un autre (pas de troll please) ?

+0 -0

C'est une question intéressante.

Je suis passé par le fonctionnel professionnellement, mais (malheureusement) assez brièvement. Pour des besoins ponctuels, sur de l'async. temps-réel, pub/sub, etc. Un domaine où ça valait le coup de tenter l'approche fonctionnelle.

On a choisi Scala car on avait des compétences en Java (au final c'était assez peu important, a posteriori) mais par contre notre environnement de travail est la JVM (Java / Groovy) ce qui signifiait qu'avec Scala, on avait l'assurance de ne pas avoir besoin de ré-écrire du code existant. (réutiliser nos propres libs).

C'est terre-à-terre, et finalement ça n'a que très peu été utilisé, mais avoir l'assurance de la JVM (libs Java, environnement "en place" sur les serveurs/machines) a beaucoup compté dans ce choix.

Et je pense que "professionnellement" c'est un argument très important. Si je devais apprendre un langage fonctionnel pour des besoins académiques ou par curiosité, je ferais sans doute un autre choix.

+0 -0

Question bonus, en toute nautralité, pourquoi c'est ce langage-là qui aurait pris le dessus et pas un autre (pas de troll please) ?

QuentinC

Y'a un truc tout bête avec le OCaml : c'est un langage français, créé et maintenu par l'INRIA, la doc de base est en français, etc. Ce qui explique dans une large mesure que ce soit le langage fonctionnel le plus utilisé dans l'enseignement en France. En Angleterre, tu trouveras beaucoup plus de Haskell dans l'enseignement, le langage étant créé et maintenu par l'Université de Glasgow. :)

+1 -0

Avez-vous commencé à utiliser les langages fonctionnels durant votre cursus scolaire ? (Si oui n’hésitez pas à préciser le nom et l’année de votre formation)

Non.

Quel langage fonctionnel utilisez-vous principalement (votre favori) ? Quels sont les autres langages fonctionnels que vous utilisez (mis à part le favori) ?

Haskell, mais c'est le seul que je connais (et je suis débutant). J'ai déjà regardé très vite fait des sources en Scheme, F# et OCaml mais je trouve ça moins élégant que le Haskell, mais l'esthétique est pas vraiment un argument valable, je doute que ça rentre dans le débat lorsqu'on choisit un langage pour un projet. Je vais regarder Coq et Why3 bientôt.

Utilisez-vous votre langage fonctionnel favori pour des projets professionnels, personnels ou les deux ?

J'ai pas encore eu l'occasion de faire un gros projet en fonctionnel (jamais fait plus de 150 lignes) et je suis pas professionnel.

Généralement, préférez-vous utiliser les langages avec un paradigme procédural ou fonctionnel ?

Depuis que j'ai découvert le fonctionnel je préfère largement ce paradigme à l'impératif (donc au procédural). Mais j'ai jeté un coup d'oeil à Swift récemment et ça a l'air pas mal (simple et cohérent).

Quels sont les langages procéduraux utilisez principalement ? Si vous en utilisez, l’utilisez-vous parce que vous l’appréciez (n’hésitez pas à citer les qualités) ou bien est-ce plus par obligation (pour gagner sa vie) ?

Python: parce que j'ai appris la programmation avec, mais avec du recul je me rend compte que son seul avantage est qu'il est simple (outre la multitude de modules qui est sympa aussi)

Sinon j'ai essayé plein d'autres langages mais j'en connais trop peu pour juger.

Dans quel cas (type de projet) éviteriez-vous d'utiliser votre langage fonctionnel ?

Dans l'état actuel des choses, Haskell est hyper chiant dès qu'on fait du graphique, en tout cas j'ai toujours eu des souci avec ça. Mais peut être qu'avec le temps on trouvera des solutions pour pallier à ce problème.

Conseilleriez-vous aux gens qui ne connaissent que le paradigme procédural d’apprendre au moins un langage fonctionnel ? Si oui pourquoi et lequel ?

Oui, parce que les débutants apprennent l'impératif comme si c'était le seul paradigme en programmation. Ça permet d'avoir un peu de recul sur notre manière de coder, même en impératif. Du coup je conseille Haskell parce que c'est le seul langage fonctionnel que je connais ._.

NB: Je suis encore débutant en programmation

Par rapport aux autres membres de Zeste de Savoir, surtout ceux qui ont répondu à ce sujet, je suis très (très) débutant. C'est pour ça que j'ai jugé important de mentionner mon niveau parce que j'ai infiniment moins de recul qu'eux, je pense.

En un an de Python t'as le temps de voir les bases et éventuellement de les approfondir un peu, ça fait de toi peut être un intermédiaire en Python, mais certainement pas en programmation. Ça rejoint ce que je disais: quand on apprend un langage, on apprend un paradigme de programmation, c'est pour ça que je pense que c'est bien de connaitre plusieurs langages de paradigmes différents (là je parlais du fonctionnel parce que c'était le sujet, mais c'est valable aussi pour la programmation logique, l'évènementiel, etc…). Surtout que mon apprentissage est quasiment que théorique, j'ai jamais fait de gros projet donc je pratique pas beaucoup.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte