Quelques notes pratiques avec SML
| Auteur | Message |
|---|---|
|
Le titre dit « quelques notes », parce que SML est tellement bien fait qu’il n’a pas de pièges, seulement des petites choses pas toujours assez intuitive, qui sont en petit nombre. Ça peut aider de les décrire. Puis ce sera peut‑être l’occasion de quelques autres notes au fil du temps, mais pas beaucoup.
Ce qui est écrit, est en supposant Successor ML, une mise à jour de la définition sur langage, dérivé du SML des années 1990 et compatible avec. Les différences ne sont pas très nombreuses mais bien pratiques. Si on défini un type enregistrement et qu’on défini une fonction sur ce type : Source SML :type t = {a: int, b: int}On peut vouloir que dans la fonction, le nom d’un membre soit renommé, par exemple, c. Intuitivement, on pourrait penser à ça : fn {a, c = b}. Mais ça se terminera par une erreur, par exemple que c n’est pas un membre de l’enregistrement t. Il faut l’écrire à dans l’autre sens, dans un sens contraire à l’intuition : fn {a, b = c}. Idem si on veut rendre anonyme le membre b : fn {a, b = _} ou fn {a, b=_} pour que ce soit plus compact. Si on a un type algébrique défini dans un module, et qu’on veut importer ce type : Source SML :structure S = struct On va souvent vouloir accéder à l’un de ses constructeurs pour créer une valeur (ce n’est pas obligatoire si des fonctions dans S renvoi une valeur de type t) ou les utiliser dans des expressions case … of. Mais ça ne marchera pas comme écrit plus haut. Intuitivement, on peut vouloir écrite “datatype t = S.t” mais ce sera une erreur de syntaxe. Il faut en fait l’écrire de cette manière un peu déroutante : “datatype t = datatype S.t”. Avec cette notation, le type est importé avec ses constructeurs. Inutile d’essayer d’importer en utilisant par exemple “val A = S.A”, ça ne marchera pas, parce que ces constructeurs ne sont pas des fonctions comme les autres. De retour aux types enregistrement. On peut avoir l’idée d’écrire des choses comme ça, parfois : Source SML :type t = {a: int, b: int}En pensant que la première clause du case correspond au cas où b est égal à 1, on se trompe, en fait c’est un renommage local de b. De la même manière avec les datatype, on peut vouloir faire ça : Source SML :datatype t = A of int En pensant que la première la correspond au cas où a est A 1, on verra que ça ne marche pas. Là aussi, ça assigne c à 1, ça ne vérifie pas que c est à 1. C’est général avec les pattern : on ne peut pas y utiliser des valeurs comme on y utilise des constantes. Ce serait pratique parfois, mais ce n’est pas prévu. Ce serait possible en théorie, mais il faut une syntaxe qui désambiguïser la signification : on assigne ou on teste ? |
|
|
Cette syntaxe est plus facile à trouver, mais mentionnée quand‑même au cas où …
Pour définir une signature SIG2 dont l’intention est d’être une extension d’une signature SIG1, il faut utiliser include : Source SML :signature SIG1 = sig Remarque : traditionnellement, les noms de signatures s’écrivent en toutes majuscules. Ça peut s’écrire aussi dans une signature anonyme : Code :signature SIG1 = sig Ici, il est fait l’économie de définir une SIG2 à part. |
|
|
Voir aussi ce message : Re: Les références et annexes.
|
|
|
Si plusieurs types d’exception sont attendues quelque part, au lieu de un seul type, alors il y a des risques de ne pas les intercepter si des parenthèses ne sont pas ajoutées autour de chaque expression interceptant une exception. Il y a une meilleure possibilité, rapportée à la fin.
Un exemple trompeur qui ne fonctionne pas : Source SML :exception Covid Si la fonction “test” envoi l’exception Covid au lieu de Flu, elle est interceptée, mais Flu ne l’est pas. Si vous voulez, essayez de deviner où ça ne va pas, mais la réponse est juste après cette ligne. Un exemple qui fonctionne : Source SML :exception Covid La seule différence, ce sont les parenthèses englobant l’expression qui gère l’exception Covid. Si un troisième type d’exception était attendu, il faudrait mettre entre parenthèse toute l’expression, avant d’ajouter le nouveau gestionnaire et ainsi de suite : Source SML :exception Covid Une meilleure écriture, est d’utiliser une syntax similaire à celle des expressions “case”. Si l’interpréteur/compilateur accepte la syntaxe de Successor ML, on peut ajouter un “|” avant le premier cas, pour que ce soit plus harmonieux. Source SML :handle |
