Je suis un débutant complet avec OCaml. Je suis récemment tombé sur cette page listant une bonne quantité de critiques envers OCaml.
Voyant que la page est assez ancienne (2007): quels sont les points de puces énumérés qui sont toujours d'actualité? Par exemple: est-il toujours vrai qu'il est impossible d'imprimer un objet générique?
Je tiens à préciser que je ne cherche pas à discuter des opinions qui y sont exprimées. Je demande si les informations répertoriées, telles que le fait que les entiers débordent sans avertissements, sont toujours correctes pour les versions plus récentes d'OCaml
Réponses:
Cet article est discuté à plusieurs endroits:
Pour résumer: oui, OCaml n'est pas un Lisp, et non, il n'est pas parfait (qu'est-ce que ça veut dire?). Je ne pense pas que les points mentionnés dans le blog soient pertinents pour les programmeurs O'Caml au quotidien.
Après avoir étudié O'Caml, je pense que c'est un langage intéressant qui peut vous aider à créer des programmes dans lesquels vous n'oseriez même pas écrire, disons C / C ++ / Java: par exemple, jetez un œil à Frama-C .
Pour une description à jour d'O'Caml, je vous encourage à lire sur ses caractéristiques : le langage promeut des techniques de vérification de type statique fortes qui permettent aux implémentations de se concentrer sur la production d'exécutions performantes, mais sûres.
Important : je ne suis pas un expert OCaml: si vous êtes l'un d'eux et voyez que j'ai écrit quelque chose d'horriblement mal, veuillez me corriger. Je modifierai ce message en conséquence.
Vérification de type statique
Faux sentiment de sécurité
C'est vrai, mais évident.
La saisie statique vous donne des preuves fiables sur un sous-ensemble des propriétés de votre programme. Sauf si vous acceptez de passer à la formalité, un programme moyen (non jouet) sera soumis à des bogues d'erreur de programmation qui ne peuvent être constatés qu'au moment de l'exécution.
C'est à ce moment que les techniques de vérification dynamique peuvent être appliquées: le compilateur OCaml a des drapeaux pour générer des exécutables avec des informations de débogage, et ainsi de suite ... Ou, il peut générer du code qui fait aveuglément confiance au programmeur et efface autant que possible les informations de type. Les programmeurs qui souhaitent des programmes robustes doivent implémenter explicitement les vérifications dynamiques.
La même chose s'applique par exemple à Common Lisp, mais inversé: les types dynamiques en premier, avec les déclarations de type optionnelles et les directives du compilateur en second.
Quelques types de base
S'applique toujours: le langage de base n'a pas changé (ou pas radicalement).
Débordement d'entier silencieux
C'est la norme dans la plupart des langues que le débordement d'entier est vérifié à la main. Je ne connais aucune bibliothèque qui effectuerait des vérifications de type pour vérifier si un débordement peut se produire.
Immuabilité du module
L'auteur mentionne Functors mais je ne vois pas comment son exemple ne peut pas être implémenté. En lisant le chapitre Modules de première classe de https://realworldocaml.org , il semble que les modules peuvent être utilisés pour composer et construire de nouveaux modules. Bien sûr, la modification d'un module existant nécessite une modification du code source, mais encore une fois, ce n'est pas inhabituel parmi les langages de programmation.
" Sémantiquement , les fonctions sont compilées EN LIGNE"
Le fil reddit ci-dessus n'est pas d'accord, disant que la liaison est résolue au moment du lien. Cependant, c'est un détail d'implémentation et je pense que l'accent sémantique se rapporte à la façon dont les fonctions sont résolues. Exemple:
Le programme ci-dessus compile et, lorsqu'il est exécuté, renvoie 5, car il
g
est défini avec la première version def
, comme si la fonction appelanteg
alignait l'appel àf
. Ce n'est pas "mauvais", soit dit en passant, c'est juste cohérent avec les règles d'occultation du nom d'O'Caml.Pour résumer : oui, les modules sont immuables . Mais ils sont également composables .
Le polymorphisme provoque des erreurs de type d'exécution
Je ne peux pas reproduire l'erreur mentionnée. Je soupçonne que c'est une erreur de compilation.
Pas de macros
En effet, il n'y a pas de macros mais des préprocesseurs (OcamlP4, OcamlP5, ...).
Wrappers (avec fichier ouvert)
Savoir comment UNWIND-PROTECT peut être utile, c'est en effet pénible de le voir absent de plus de langues. Voici quelques options:
Des endroits
Je ne pense pas que des références généralisées existent dans OCaml.
Suckiness langue mineure
L'enfer des noms de champ d'enregistrement
Vrai, mais vous devez utiliser des modules:
Syntaxe
S'applique toujours (mais vraiment, ce n'est qu'une syntaxe).
Pas de polymorphisme
S'applique toujours, mais d'une certaine façon, il y a des gens qui préfèrent cela au lieu de la tour numérique de Lisp (je ne sais pas pourquoi). Je suppose que cela aide à l'inférence de type.
Ensembles de fonctions incohérents
Voir le projet OCaml Batteries Inclus . En particulier, BatArray , pour un exemple de
map2
pour les tableaux.Pas de variables dynamiques
Peut être implémenté:
Facultatif ~ les arguments sont nuls
Par restriction de langue, vous ne pouvez pas mélanger des arguments facultatifs et des mots clés en Common Lisp. Est-ce à dire que ça craint? (bien sûr, cela peut être changé avec des macros (voir par exemple ma réponse )). Voir la documentation d' O'Caml pour les arguments facultatifs et nommés dans O'Caml.
Incohérence partielle de l'application d'argument
Je ne pense pas que ce soit vraiment ennuyeux dans la pratique.
Lisibilité de l'arithmétique
C'est vrai, mais vous pouvez utiliser R ou Python pour les problèmes numériques si vous préférez.
Résolution silencieuse des conflits de noms
S'applique toujours, mais notez que cela est bien documenté.
Pas d'entrée / sortie d'objet
S'applique toujours.
Implémentation, bibliothèques
Celles-ci changent tous les jours: il n'y a pas de réponse définitive.
Finalement,
... s'applique toujours.
la source
Faux sentiment de sécurité . Ça n'a pas de sens.
Quelques types de base . OCaml a maintenant des octets et des tableaux d'octets mais pas de chaînes Unicode intégrées, d'entiers 16 bits, d'entiers non signés, de flottants 32 bits, de vecteurs ou de matrices. Des bibliothèques tierces en fournissent certaines.
Débordement d'entier silencieux . Inchangé mais ce n'était jamais un problème.
Immuabilité du module . Sa recommandation que les fonctions et les modules devraient être mutables est un sombre retour à Lisp et une très mauvaise idée. Vous pouvez remplacer les modules en utilisant
include
si vous le souhaitez, mais vous ne pouvez pas les muter, bien sûr.Le polymorphisme provoque des erreurs de type au moment de l'exécution . C'est un gros problème avec OCaml et il n'a pas été corrigé. À mesure que vos types évoluent vers l'égalité polymorphe, la comparaison et le hachage commencent à échouer lorsqu'ils rencontrent des types tels que des fonctions et le débogage du problème est très difficile. F # a une excellente solution à ce problème.
Pas de macros . Ironiquement, quand il a écrit cet OCaml avait en fait un support complet pour les macros, mais ils ont maintenant décidé de retirer la fonctionnalité.
Emballages . C'était un vrai problème et il n'a pas été résolu. Il n'y a toujours pas de
try ... finally
construction dans le langage OCaml et aucun wrapper l'implémentant dans stdlib.Des lieux . Inchangé mais sans problème.
Enregistrer l'enfer de nommage sur le terrain . Structurez correctement votre code à l'aide de modules.
Syntaxe . Inchangé mais sans problème.
Pas de polymorphisme . C'était surtout un non-sens quand il l'a écrit et rien n'a changé.
Ensembles de fonctions incohérents . OCaml n'a toujours pas de
cons
fonction. C'est très bien. Je ne veux pas de trucs Lisp dans ma langue, merci.Pas de variables dynamiques . C'était une bonne chose à propos d'OCaml. C'est toujours une bonne chose à propos d'OCaml.
Les arguments facultatifs sont nulles . Arguments optionnels rock. J'ai harcelé Microsoft pour lui faire ajouter des arguments facultatifs à F #.
Incohérence partielle de l'application d'argument . Eh?
Lisibilité de l'arithmétique . Cela a changé depuis que j'ai cessé d'utiliser OCaml il y a environ 8 ans. Apparemment, vous pouvez maintenant le faire
Int64.((q * n - s * s) / (n - 1L))
.Résolution silencieuse des conflits de noms . Il essayait de faire un développement logiciel complet dans le REPL comme vous le feriez dans Lisp. Ne faites pas cela dans OCaml. Utilisez les fichiers et la compilation par lots ayant recours au REPL uniquement pour les tests, l'exécution de code jetable et l'informatique technique interactive.
Ordre d'évaluation . C'était mal quand il l'a écrit. L'ordre d'évaluation n'est pas défini dans OCaml.
Aucun objet entrée / sortie . Il a cité une bibliothèque tierce qui avait déjà résolu ce "problème".
Le compilateur s'arrête après la première erreur . Eh?
Aucune trace de pile pour les exécutables compilés en mode natif . Fixé.
Le débogueur craint . Je n'ai jamais utilisé le débogueur. La vérification de type statique attrape presque tous mes bogues.
GC craint . J'ai trouvé que le GC d'OCaml était superbe à l'exception d'un problème majeur: le verrouillage global empêche la programmation parallèle.
Pas de déclarations directes implicites . La récursion mutuelle est explicite par conception dans tous les ML. La seule bizarrerie est que les
type
définitions sont récursives par défaut tandis que leslet
liaisons sont non récursives par défaut.La fonction ronde est absente . OCaml a toujours un stdlib simple mais des bibliothèques tierces comme Jane St's Core fournissent
round
et amis.Listes .
List.map
n'est toujours pas récursif de queue. J'ai soumis des correctifs pour corriger de graves bogues comme celui-ci et j'ai dû attendre des années avant qu'ils n'apparaissent dans les versions. Les listes sont toujours immuables, bien sûr. Et ils devraient l'être.La vitesse . Je crois que les temps de compilation pour les grandes variantes polymorphes ont été corrigés.
Correspondance de motif . Un triomphe d'espoir sur la réalité. La communauté Lisp n'a pas réussi à le faire. D'où ma 10ème règle: tout programme Lisp suffisamment compliqué contient une implémentation ad hoc, spécifiée de manière informelle et contenant des bogues de la moitié du compilateur de correspondance de modèle d'OCaml.
Quand il a écrit que vous ne pouviez pas simplement faire:
mais vous pouvez appeler la jolie imprimante du niveau supérieur en tant qu'appel de bibliothèque, en lui donnant les informations de type nécessaires. Et il y avait une macro que vous pouvez utiliser pour annoter les structures de données afin d'avoir de jolies imprimantes générées automatiquement.
la source
cons
donne un mauvais ton (l'article original est une diatribe, mais vous n'avez pas besoin de le copier).+
sur des entiers, des flottants et des complexes, mais vous pouvez également définir vos propres types et ajouter une surcharge pour+
travailler sur votre type. Cela fournit la brièveté et la lisibilité de Lisp ou Haskell avec les bonnes performances prévisibles de SML ou OCaml, réalisant quelque chose qu'aucun autre langage ne fait.