Apprendre la programmation fonctionnelle avec OCaml

Nouvelle session du MOOC de Paris 7 sur FUN

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut,

L'équipe d'enseignants-chercheurs de Paris 7 qui s'occupe du MOOC OCaml & programmation fonctionnelle sur France Universités Numérique lance une nouvelle session de son MOOC, qui commence le 26 septembre. Ils estiment qu'il faut entre 2 et 6h par semaine pour suivre le cours mais sans aucun doute pour des gens qui ont déjà un peu programmé ça sera plus facile. C'est prévu pour les débutants, cependant le dernier chapitre porte sur les modules, qui sont à la fois une spécificité et un point fort des langages ML dont OCaml est issu (et qui ne fonctionnent pas tout à fait comme les modules que l'on rencontre dans d'autres langages).

Le cours est en anglais, mais des sous-titres français sont disponibles, et de toute façon tous les auteurs parlent français et sont très disponibles pour répondre aux questions.

Une dépêche très complète a été publiée sur LinuxFR pour l'occasion.

Édité par anonyme

+5 -0
Staff

Cette réponse a aidé l'auteur du sujet

Salut,

J'ai vu la dépêche sur LinuxFr, et j'ai l'intention de m'inscrire. Ça fait un moment que j'essaye d'apprendre un langage fonctionnel, mais la logique déroutante quand on vient de l'impératif me fait lâcher au bout de quelques heures à chaque fois. C'est l'occasion de se lancer.

D'ailleurs, si d'autres agrumes sont intéressés, ça pourrait être intéressant de discuter des exercices sur lesquels on aura planché (et éventuellement lamentablement échoué :P ). D'autant plus que je crois qu'il y a quelques programmeurs fonctionnels dans le coin.

Édit : Par contre, l'un des commentateurs de la dépêche disait que les 2 à 6 heures lui avait été très insuffisant lorsqu'il avais participé l'an passé.

Édité par Gabbro

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Ayant déjà une certaine expérience en Ocaml (il parait même que je donne des cours sur ce langage), je ne compte pas suivre le MOOC (même si j'adore l'accent italien de Di Cosmo). Par contre, si certaines personnes ont besoin d'aide, ce sera un plaisir de les aider :) .

+0 -0
Auteur du sujet

Cette réponse a aidé l'auteur du sujet

La bibliothèque standard est pas terrible ce qui a provoqué l'apparition de deux bibliothèques (Core et Batteries), la manipulation de flottants est chiante parce qu'il faut remplacer l'opérateur + par +. et à titre personnel, j'ai horreur d'utiliser de l'impératif en OCaml. Ceci dit c'est quand même un langage que j'aime bien.

+2 -0

Cette réponse a aidé l'auteur du sujet

Les points que Grimur soulève sont vrais, mais ils relèvent plus de la convenance personnelle que des limites du langage :

  • C'est vrai, la bibliothèque standard est assez peu fournie, même s'il y a des efforts dans ce sens. Mais Core et Batteries (et d'autres, comme Containers) sont des projets qui pallient tout à fait ce manque. On peut être insatisfait du double effort (encore qu'à part pour des raisons de principe, ça ne gêne en pratique personne) ou du fait qu'il faille installer un paquet supplémentaire (mais bon, qui en 2016 programme quelque chose d'un minimum conséquent uniquement avec la stdlib de son langage ?), mais ce n'est pas une limitation en soi.
  • C'est effectivement un peu pénible de devoir écrire +. pour additionner deux flottants, mais :
    • Si on ne travaille qu'avec des flottants, on open Float et c'est réglé
    • Les modules implicites qui finiront bien par arriver dans le trunk règlent ce problème d'une façon élégante (en gros, comme haskell, mais en mieux :p )
    • En attendant, c'est nécessaire pour l'inférence de types. Concrètement, par rapport aux langages que les gens d'ici ont l'habitude d'utiliser (comme Java ou Python), c'est un petit mal pour un plus grand bien (pas besoin d'écrire les types, le typeur les devine tout seul, et c'est fait à la compilation).
    • Dans tous les cas, ce n'est encore pas une limitation à proprement parler du langage, juste un léger inconfort quand on écrit un programme qui utilise beaucoup entiers et flottants (à titre personnel, ça ne m'est jamais arrivé).
  • L'impératif en OCaml est effectivement moins agréable à utiliser que le style fonctionnel, et un peu plus lourd que dans des langages pensés avant tout pour l'impératif comme Python. Mais rien n'oblige à programmer en impératif, et si vraiment on en a besoin, c'est encore un inconfort plus qu'une limitation (c'est quelques ! à rajouter, rien de plus).

Qu'on soit bien clairs : OCaml n'est évidemment pas un langage parfait, il a ses défauts. Ça n'en reste pas moins un excellent langage, même si les goûts personnels de chacun peuvent le porter à moins apprécier certaines de ses caractéristiques.

Pour répondre tout de même à la question d'Unknown, OCaml est à l'origine un langage créé par des chercheurs, pour leurs recherches (pour la petite histoire, c'était initialement un langage qui a été créé pour pouvoir implémenter un autre langage, Coq). Ça veut dire plusieurs choses :

  • L'état de la recherche en France étant ce qu'il est, c'est un projet qui a bénéficié de beaucoup moins de financements que quelque chose comme Java ou Python.
  • Pendant longtemps, les mainteneurs du langage se préoccupaient peu du confort d'utilisation par des programmeurs lambda : le but était d'utiliser le langage pour faire de la recherche, et les efforts de maintenance supplémentaires pour que d'autres gens puissent s'en servir ne correspondaient pas à cet objectif.
  • La recherche et la science attirant peu de monde (combien de personnes persistent encore à ne voir l'informatique que comme un outil ?) et se préoccupant peu de communications, la communauté d'utilisateurs est longtemps restée très faible.

Ces trois défauts sont maintenant très nettement moins importants qu'il y a une vingtaine d'années, et de nombreux efforts sont faits dans ce sens, mais les choses mettent du temps à évoluer. La principale "limitation" qui en découle est que le nombre de librairies disponibles en OCaml est plus faible que dans les autres langages. Selon le domaine dans lequel tu travailles, ça peut être un problème (par exemple, il n'y a à ma connaissance pas grand chose pour faire de la vision par ordinateur), ou pas du tout (par exemple, puisque c'est une question qui revient souvent, on a un très bon framework Web en OCaml). Quant à la communauté, elle est faible, mais particulièrement active : c'est en pratique facile de trouver de l'aide rapidement à n'importe quel niveau.

Pour compléter, même si c'est certainement très loin de tes préoccupations, OCaml n'est pas adapté pour écrire des systèmes temps réel avec des très fortes contraintes de réactivité. Pour des systèmes embarqués avec des ressources très limitées, ça va être aussi un peu compliqué. Cela dit, c'est deux domaines de niche où le C++ et le C règnent actuellement de fait en maître, et si tu poses ce genre de question, c'est très peu probable que tu aies ces besoins, OCaml restant un langage avec d'excellentes performances (bien meilleures que Python, par exemple).

Édité par Eusèbe

+2 -0
Staff

Il y a un point qui n'est pas cité et pourtant me paraît important justement si on ne vient pas du milieu de la recherche : la portabilité. Il me semble qu'Ocaml et Windows ne font pas bon ménage non ?

L'autre soucis d'Ocaml qui m'a gêné à titre personnel c'est le tooling. J'avais suivi un cours de GL où à 12, on avait programmé un jeu en Ocaml. Même si on avait réussi à avoir un jeu plutôt cool à la fin, le gros problème que j'avais eu c'était surtout au niveau des outils autour pour build le projet, faire des tests unitaires, générer la documentation etc…

Même si il y a des outils qui existent (Ocamlbuild, oUnit, Ocamldoc), certains sont assez limités ou bien il manque de la documentation.

Enfin, Ocaml peu poser problème à apprendre seul. Malheureusement, les messages d'erreur du compilateur ne sont pas toujours facile à interpréter quand on apprend le langage seul.

Par exemple si on écrit

1
[1,2,3]

au lieu de

1
[1;2;3]

En fonction du contexte, le compilateur va (voir même ne pas produire du tout) de message d'erreur car même si la deuxième syntaxe correspond généralement à ce que l'on souhaite faire, à savoir une liste contenant 3 éléments, la première correspond à une liste contenant 1 élément qui est un triplet. Pour les experts, ça parait évident, mais j'ai eu en TP, 2-3 étudiants qui ont bloqué quelques dizaines de minutes avant de se résigner à m'appeler pour comprendre le problème.

Édité par Saroupille

+0 -0

Il y a un point qui n'est pas cité et pourtant me paraît important justement si on ne vient pas du milieu de la recherche : la portabilité. Il me semble qu'Ocaml et Windows ne font pas bon ménage non ?

J'ai effectivement hésité à mentionner ça. Je sais qu'il y a un effort assez constant de ce côté (notamment de la part de Lexifi il me semble), et je ne sais pas à quel point c'est vraiment difficile ou seulement un peu pénible de programmer sous Windows avec OCaml. En tout cas, pour un débutant, ça ne posera aucun problème.

L'autre soucis d'Ocaml qui m'a gêné à titre personnel c'est le tooling. J'avais suivi un cours de GL où à 12, on avait programmé un jeu en Ocaml. Même si on avait réussi à avoir un jeu plutôt cool à la fin, le gros problème que j'avais eu c'était surtout au niveau des outils autour pour build le projet, faire des tests unitaires, générer la documentation etc…

Même si il y a des outils qui existent (Ocamlbuild, oUnit, Ocamldoc), certains sont assez limités ou bien il manque de la documentation.

Oui, c'était un peu elliptique mais je mettais ça avec les libs. C'est un peu le même constat : il manque sans aucun doute des choses, mais très souvent ce qu'on a suffit largement (et comme toujours, des gens bossent là dessus, même si ça prend du temps, surtout pour des raisons de moyen).

Enfin, Ocaml peu poser problème à apprendre seul. Malheureusement, les messages d'erreur du compilateur ne sont pas toujours facile à interpréter quand on apprend le langage seul.

Par exemple si on écrit

1
[1,2,3]

au lieu de

1
[1;2;3]

Même remarque que plus haut : on peut trouver que c'est un problème, mais c'est une question de confort personnel, pas une limitation. Il y a ce genre de problème dans tous les langages, plus ou moins prononcé et plus ou moins apparent selon l'habitude des utilisateurs, je ne pense pas que ce soit très pertinent de présenter ça comme un défaut qui limite vraiment.

Source:Saroupille

+0 -0
Staff

Bonjour à tous,

j'ai enfin eu le temps de m'attaquer sérieusement au mooc. Lors des exercices sur les fonctions récursives, j'ai répondu aux problèmes, mais j'ai l'impression que ce n'était pas très idiomatique. Typiquement, on me demande un pgcd, j'ai fait ça :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
let gcd n m =
(* Vérfie si num est divisible par i *)
  let divide i num =
    if num mod i = 0 then true else false
  in
(* Fonction récursive pour faire comme une boucle *)
  let rec pgdc n m i =
    if divide i n && divide i m then
      i
    else pgdc n m (i-1)
  in

  pgdc n m (max n m)
;;

La fonction récursive que je créé me permet de faire comme avec les boucles, puis de cacher le tout. Ma question est : est-ce que c'est un truc comme ça qu'il faut faire, ou fais-je du mauvais code à cause de mes habitudes impératives.

Merci.

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+0 -0

Ça c'est effectivement pas très idiomatique :

1
2
let divide i num =
    if num mod i = 0 then true else false

C'est équivalent à :

1
2
let divide i num =
  num mod i = 0

Sinon, en soit, la fonction pgdc (malgré son nom contestataire :p) n'a rien de non idiomatique. Par contre, effectivement elle n'est pas très efficace, et elle ne "termine pas" sur pgcd(0, 0) (ce qui a bien un sens quand on considère la "vraie" définition du PGCD). Elle ne marche pas très bien pour les négatifs non plus (mais l'autre fonction citée plus haut renvoie des PGCD négatifs dans ce cas, ce qui n'est pas très conventionnel).

Staff

Coucou,

J'ai bien du mal à comprendre comment utiliser, et quel est l'intérêt de, fold.

Typiquement, j'ai l'énoncé suivant,

Write a function filter : ('a -> bool) -> 'a list -> 'a list that takes a predicate p (a function returning a boolean) and a list l and returns all the elements of l that satisfy p (for which p returns true).

Et je tourne en rond sans trop savoir quoi faire. Le faire sans fold ne me pose pas de soucis, mais le but n'est pas là.

1
2
3
4
let rec filter p = function
  | [] -> []
  | hd::tl -> if p hd then hd :: filter p tl else filter p tl 
;;

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+0 -0

Salut,

fold c'est ce qui va te permettre de ne pas traiter explicitement l'appel récursif.

Ici, tu traites ta liste comme étant composée d'une tête et d'une queue, tu rappelles ta fonction sur la queue et tu effectues un traitement entre la tête et le retour de cet appel récursif.

C'est exactement ce que fait fold_right, prenant en premier paramètre la fonction à utiliser pour le traitement (que faire de la tête et du retour de l'appel récursif). Le principe revient au même avec fold_left, mais en traitant les éléments à partir de la fin.

Staff

Il m'a fallu un bon moment, et resortir un exemple très proche pour trouver une solution,

1
2
3
4
5
6
let filter (p: 'a -> bool) (l: 'a list) =
  List.fold_left
    (fun ll hd -> if p hd then hd :: ll else ll)
    []
    l
;;

Reste une question de taille : quel est l'intérêt de fold ? Je n'ai pas l'impression que ça apporte en performance ou en clarté, ni que ça permette des trucs extraordinaire.

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+0 -0

Dans le cas présent, l'utilité de fold est pas évidente, vu que l'opération à appeler n'existe pas déjà.

Par contre pour calculer la somme des termes d'une liste, ça donne quelque chose d'assez simple :

1
fold_left (+) 0 [1; 2; 3; 4; 5]

Ou encore

1
2
let sum = fold_left (+) 0 in
    sum [1; 2; 3; 4; 5]
Staff

Je trouve que ça apporte en clarté quand on sait ce que fait fold. Surtout j'ai pris l'habitude en général de me dire que lorsqu'une personne écrit une fonction récursivement sur une liste et qu'elle n'utilise pas fold, en général elle fait des choses plus compliquées.

Cependant, à titre d'exercise, tu peux considérer qu'une liste est axiomatisée par fold_left par exemple, et réimplementer toutes les autres fonctions du module List à coup de fold_left.

Édité par Saroupille

+1 -0
Staff

Salut,

J’arrête le MOOC un peu avant sa fin (sans l'avoir tout à fait fini, d'ailleurs). Je me demandais ce que vous (si d'autres l'ont fait) en aviez pensé ?

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+0 -0
Staff

Parce que je n'ai pas eu le temps de commencer le projet, et que ça finit dans une semaine et demi.

De plus, je suis globalement déçu de ce MOOC, tant par côté technique (leur truc pour taper le code en ligne est très peu pratique, et obligé d'y passer pour la validation), que, plus grave, par la pédagogie, qui n'est clairement pas au rendez-vous. Je me suis accroché lors de la semaine 3 qui était catastrophique de ce point de vue, en pensant que c'était juste un cours, mais en faisant le point pour leur faire le retour demandé, je me suis rendu compte que c'était général. Bref, je préfère arrêter les frais.

C'est aussi pour ça que je voulais savoir s'il y avait d'autres retour.

Hier, dans le parc, j'ai vu une petite vieille entourée de dinosaures aviens. Je donne pas cher de sa peau.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

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