Author: Christian.Queinnec@lip6.fr

## Langages fonctionnels proches

Il existe plusieurs langages proches d'Objective CAML, soit par le côté fonctionnel, soit par le typage. Objective CAML est issu de la famille ML, et possède donc des cousins dont les plus proches sont outre-atlantique et outre-manche dans la lignée de SML (Standard ML). La famille Lisp, et en particulier le langage Scheme, diffère de ML principalement par son typage dynamique. Deux langages paresseux, Miranda et Haskell, reprennent ou étendent le typage de ML dans le cadre de l'évaluation retardée. Deux langages fonctionnels Erlang et SCOL développés respectivement par les sociétés Ericsson et Cryo-Networks sont tournés vers la communication.

### Famille ML

La famille ML comprend deux branches principales : Caml (Categorical Abstract Machine Language) et ses dérivés Caml-Light et Objective CAML, SML (Standard ML) et ses descendants SML/NJ et mossml. Caml, l'ancêtre, a été développé entre 1986 et 1990 par le projet FORMEL de l'INRIA en collaboration avec l'Université Paris 7 et l'École Normale Supérieure. Son implantation reposait sur la bibliothèque d'exécution de Le_Lisp. Il intégrait dans le langage la définition de grammaires et d'afficheurs ce qui permet la communication de valeurs entre le langage décrit et Caml. Son système de types était plus contraignant pour les valeurs physiquement modifiables en ce qu'il n'autorisait pas que de telles valeurs fussent polymorphes. Son premier descendant, Caml-Light, n'utilisait plus la machine CAM, mais la Zinc pour l'implantation. Le nom a néanmoins été conservé pour montrer sa filiation. Il a apporté une implantation plus légère en optimisant l'allocation des fermetures et utilisait un GC performant précurseur du GC actuel. Cet allégement permettait de l'utiliser sur les micros-ordinateurs de l'époque. Les différentes versions de Caml-Light ont évolué vers le typage actuel des traits impératifs et se sont enrichies de nombreuses bibliothèques. Le rejeton suivant, Caml Special Light ou CSL, a introduit les modules paramétrés et le compilateur natif. Enfin le benjamin est actuellement Objective CAML qui ajoute principalement l'extension objet à CSL. Comme il n'y a jamais eu de spécification complète du langage Caml, ces différentes évolutions ont pu s'effectuer en toute liberté.
L'approche SML a été inverse. La spécification formelle [MTH90] a été donnée avant la première implantation. Elle est difficile à lire, et un deuxième livre en donne un commentaire ([MT91]). Cette démarche, spécification puis implantation, a permis la réalisation de plusieurs implantations, dont la plus connue est SML/NJ (Standard ML of New Jersey) de Lucent (ex-ATT). Dès l'origine, SML a intégré des modules paramétrés. Son système de typage initial était différent de celui de Caml pour les traits impératifs en introduisant un niveau de faiblesse sur les variables de type. Les différences entre les deux langages sont détaillées dans [CKL96]. Ces différences s'estompent avec le temps. Les deux familles ont le même système de type pour le noyau fonctionnel et impératif, Objective CAML possède maintenant des modules paramétrés. SML a aussi subi des évolutions, le rapprochant d'Objective CAML comme pour les types enregistrements. Si les deux langages ne fusionnent pas, cela provient principalement de leur développement séparé. Il est à noter qu'il existe un environnement de développement commercial pour SML, MLWorks, de chez Harlequin :

### Lien

http://www.harlequin.com/products/

Une implantation de SML, `mossml`, reposant sur la bibliothèque d'exécution de Caml-Light a aussi été implantée.

### Scheme

Le langage Scheme (1975) est un dialecte du langage Lisp (1960). Il est normalisé (IEEE Std 1178-1990). C'est un langage fonctionnel à évaluation stricte, muni de traits impératifs, typé dynamiquement. Sa syntaxe est régulière et particulière par l'usage des parenthèses. La structure de donnée principale est la paire pointée (équivalent du couple ML) avec laquelle on construit des listes possiblement hétérogènes. La boucle principale d'une boucle d'interaction Scheme s'écrit `(print (eval (read)))`. La fonction `read` lit l'entrée standard et construit une expression Scheme. La fonction `eval` évalue l'expression construite et la fonction `print` affiche le résultat. Scheme possède un système de macro-expansion très pratique qui, associé à la fonction `eval`, permet de construire facilement des extensions du langage. Il permet non seulement d'effectuer des ruptures de calcul (exceptions) mais aussi des reprises de calcul grâce aux continuations. Une continuation correspond à un point de calcul. La forme spéciale `call_cc` lance un calcul avec la possibilité de reprendre celui-ci au niveau de la continuation courante, c'est à dire du retour de ce calcul. Il existe de très nombreuses implantation de Scheme. Il est même utilisé comme langage de macros pour le logiciel de retouche d'images GIMP. Scheme est un excellent laboratoire expérimental pour l'implantation de nouveaux concepts de programmation séquentielle ou parallèle (grâce aux continuations).

### Langages à évaluation retardée

À la différence de ML ou Lisp, les langages à évaluation retardée ne calculent pas les paramètres d'appel des fonctions à leur passage, mais quand l'évaluation du corps de la fonction le nécessite. Il existe une version << paresseuse >> de ML appelée Lazy ML mais les représentants principaux de cette famille de langages sont Miranda et Haskell.

#### Miranda

Miranda([Tur85]) est un langage fonctionnel pur. C'est à dire sans effet de bord. Un programme Miranda est une suite d'équations définissant les fonctions et les structures de données.

### Lien

http://www.engin.umd.umich.edu/CIS/course.des/cis400/miranda/miranda.html

Par exemple la fonction fib se définit ainsi :

     fib a = 1, a=0
           = 1, a=1
           = fib(a-1) + fib(a-2), a>1

La sélection des équations se fait soit par des gardes (expressions conditionnelles) comme ci-dessus, soit par un filtrage de motif comme dans l'exemple ci-dessous :

    fib 0 = 1
    fib 1 = 1
    fib a = fib(a-1)+ fib(a-2)

Ces deux méthodes peuvent se mélanger.
Les fonctions sont d'ordre supérieur et peuvent être évaluées partiellement. L'évaluation est paresseuse, aucune sous-expression n'est calculée jusqu'au moment où sa valeur devient nécessaire. Ainsi, les listes Miranda sont naturellement des flots.
Miranda a une syntaxe concise pour les structures infinies (listes, ensembles) : `[1..]` représente la liste de tous les entiers. La liste des valeurs de la fonction de Fibonacci s'écrit brièvement : `fibs = [a | (a,b) <- (1,1),(b,a+b)..]`. Comme les valeurs ne sont calculées que pour leur utilisation, la déclaration de `fibs` ne coûte rien.
Miranda est fortement typé en utilisant un système de type à la Hindley-Milner. Sa discipline de type est essentiellement la même que ML. Il accepte la définition de données par l'utilisateur.
Miranda est l'archétype des langages fonctionnels purs paresseux.

#### Haskell

Le site principal du langage Haskell contient les rapports de définition du langage et de ses bibliothèques, ainsi que les principales implantations de celui-ci.

### Lien

http://www.haskell.org

Plusieurs ouvrages sont consacrés à la programmation fonctionnelle en Haskell, un des plus récents est [Tho99].
C'est un langage qui reprend presque tous les nouveaux concepts des langages fonctionnels. Il est pur (sans effet de bord), paresseux (non-strict), muni d'un polymorphisme ad hoc (pour la surcharge) en plus du polymorphisme paramétrique à la ML.

##### Polymorphisme ad hoc

Ce système est différent du polymorphisme vu jusqu'à présent. En ML une fonction polymorphe ne regarde pas ses arguments polymorphes. Le traitement est identique pour tous les types. En Haskell c'est le contraire. Une fonction polymorphe peut avoir un comportement différent selon le type de ses arguments polymorphes. Cela autorise la surcharge de fonctions.
L'idée de base est de définir des types de classes qui regroupent des ensembles de fonctions surchargées. Une déclaration de classe définit une nouvelle classe et les opérateurs que celle-ci autorise. Une déclaration d'instance (d'une classe) indique qu'un certain type est une instance d'une classe. Cela inclut la définition des opérateurs surchargés de sa classe pour ce type.
Par exemple la classe `Num` a la déclaration suivante :

    class Num a where
      (+)    :: a -> a -> a
      negate :: a -> a

On peut maintenant déclarer une instance `Int` de la classe `Num` de cette manière :

    instance Num Int where
      x + y    =  addInt x y
      negate x = negateInt x

Et l'instance `Float` :

    instance Num Float where
      x + y    =  addFloat x y
      negate x = negateFloat x

L'application de `negate` `Num` aura un comportement différent si l'argument est de l'instance `Int` ou `Float`.
L'autre intérêt des classes provient de l'héritage entre classes. La classe descendante récupère les fonctions déclarées par son ancêtre. Ses instances peuvent en modifier le comportement.

##### Autres caractéristiques

Les autres caractéristiques du langage Haskell sont principalement les suivantes :

- un système d'entrées-sorties purement fonctionnel utilisant des monades;
- les tableaux sont construits paresseusement;
- les vues qui permettent différentes représentations d'un même type de données.

En fait il contient à peu près tous les traits pointus issus de la recherche dans le domaine des langages fonctionnels. C'est son avantage et son inconvénient.

### Langages de communication

#### ERLANG

ERLANG est un langage fonctionnel typé dynamiquement pour la programmation concurrente. Il a été développé par la société Ericsson dans le cadre d'applications pour les télécommunications. Il est maintenant en open source. Le site principal d'accès au langage est le suivant :

### Lien

http://www.erlang.org

Il est conçu pour que la création de processus et leur communication soient aisées. Les communications se font par envoi de messages et elles peuvent être soumises à des délais. Il est facile de définir des protocoles via des ports. Chaque processus possède son propre dictionnaire de définition. La gestion des erreurs utilise un mécanisme d'exceptions et de signaux qui peuvent se propager entre les processus. De nombreuses applications de téléphonie ont été réalisées avec Erlang, faisant gagner un temps de développement non négligeable.

#### SCOL

Le langage SCOL est un langage de communication pour la construction de mondes 3D. Il est développé par la société Cryo Networks :

### Lien

http://www.cryo-networks.com

Son noyau est proche de celui de Caml : il est fonctionnel, statiquement typé, polymorphe paramétrique avec inférence de types. Il est << multimedia >> grâce à ses API pour le son, la 2D et la 3D. Le moteur 3D est très efficace. L'originalité de SCOL provient de la communication entre machines virtuelles au travers de canaux. Un canal est un couple (environnement, liaison réseau). La liaison est une socket (TCP ou UDP).
L'originalité de SCOL est d'avoir résolu simplement le problème de la sécurisation de code téléchargé : seul le texte des programmes circule sur le réseau. La machine réceptrice type le programme passé puis l'exécute garantissant que le code produit provient bien du compilateur officiel. Pour mettre en oeuvre une telle solution, sans sacrifier la vitesse de transfert et de réception, le choix d'un langage fonctionnel statiquement typé s'est imposé pour la concision des sources qu'il autorise.