mercredi 30 septembre 2009

Erlang : guide de survie : Le démarrage

Bon voici le récit de mes premiers essais avec Erlang.
Après un échec cuisant avec Haskell pour sortir quelques lignes de code, je refais une tentative avec Erlang.

1) Le lancement du shell : erl , puis crtl-g pour passer en mode JCL (lancer ou arrêter les processus)

2) Lancement du menu graphique depuis le shell erl : toolbar:start().
Chaque instruction se termine par un '.' (point).

3) Compilation dans le shell : c(nom_du_programme). ou en ligne de commande
erlc . On obtient des fichiers avec l'extension 'beam'.
Très vite il est nécessaire de se creer un Makefile pour automatiser la compilation. Il existe un automake qui permet de génerer des squelettes pour des projets avec OTP (Open Telecom Platform).
Exemple de mon Makefile de base :

# leave these lines alone
.SUFFIXES: .erl .beam .yrl

.erl.beam:
erlc -W $<

.yrl.erl:
erlc -W $<

ERL = erl -boot start_clean

# Here's a list of the erlang modules you want compiling
# If the modules don't fit onto one line add a \ character
# to the end of the line and continue on the next line

# Edit the lines below
MODS = fileinfo truncate

# The first target in any makefile is the default target.
# If you just type "make" then "make all" is assumed (because
# "all" is the first target in this makefile)

all: compile

compile: ${MODS:%=%.beam}

## special compilation requirements are added here


## run an application from the makefile
run:
erl -noshell -s truncate main /root/Desktop/Lost.last.mkv

# remove all the code

clean:
rm -rf *.beam erl_crash.dump






L'entrée 'run' permet de lancer le programme avec les bonnes options pour éviter les saisies fastidieuses.

4) Le lancement en ligne de commande d'un programme:

erl -noshell -s nom_du_module fonction_du module parametre

Un programme lancé de cette façon ne s'arrête jamais , il faut ajouter un exit ou encore mieux : un init:stop(). Si le programme lance des processus par spawn, l'arret du processus père met fin aux processus fils.

5) Pour envoyer un message sur la console l'équivalent d'un print "coucou" se fait par l'instruction io:format("coucou",[]) , un peu comme l'instruction printf en C. Les règles de formatage sont plus réduites qu'en C:
'~s' pour une chaîne de caractère
'~w' pour un type quelconque (entier ,chaine,tuple)
'~p' pour une présentation en ligne.
'~f' nombre
La syntaxe est longueur.precision.padding

Exemple: ~10.2.0f donne : longeur totale 10 , 2 chiffres après la virgule et des '0' en complement.
Le '~n' donne un retour charriot '\n'.

Pour formater une variable au moment de l'assignation:
T= io_lib:format("le texte est ~w",['"ci"]).

Autre exemple: charge des entiers sur 2 caracteres, avec 0 en tête.
Texte= lists:flatten( io_lib:format("~2..0w",[I])),

6) Structure d'un programme .
Si la résolution d'un probleme peut se faire de manière linéaire , il ne sert à rien de le faire en Erlang. Par contre si on désire faire travailler plusieurs processus en même temps (concurrent) , l'Erlang est le langage qui est fait pour ca.
L'unité de base est le module , le module regroupe des fonctions. On peut classifier les fonctions en 3 catégories
- Les fonctions autonomes qui réalisent des traitements
- Des fonctions de supervision, qui lancent et gèrent les fonctions autonomes
- Les fonctions qui charpentent le programme et les données (gestion de la configuration, accès aux structures).

il est recommandé d'organiser le code en trois groupes:
- Les fichiers d'entete (hrl , comme les fichiers header en C) .
- Un fichier par module , un module par fonctions connexes
- Un fichier regroupant les fonctions d'intendance et le superviseur.
exemple :

-module (truncate).
-export([main/1,console/1,launcher/2]).
-define(GO2OCTET, 1073741824). %ratio de conversion
-define(TRUNK, 104857600). % taille de morceaux
-define(MOTIF, "trunk_%%.mkv"). % nom en sortie
-include("structures.hrl").


Dans l'ordre : le nom du module , les fonctions que le module expose (exporte) , la définition de quelques macros, l'include vers les fichiers headers. On trouvera rarement des clauses d'import. Il suffit d'appleler autre_module:fonction() pour que le compilateur recherche autre_module.beam.

7) Les structures de données
Comme en C, il est possible de manipuler des 'record'. Ces structures permettent de manipuler des données organisées.
Exemple :

%% La description dun segment
-record(segment,{nom,debut,longueur}).
create_segment(Nom,Debut,Longueur)->
#segment{nom = Nom,
debut=Debut,
longueur=Longueur}.


Le fichier contient la description de la structure et les fonctions pour la manipuler (create_ ou new ou foobar) .

Pour retrouver les données :

Nom_segment =H#segment.nom ,
Debut_segment =H#segment.debut,
Longueur_segment =H#segment.longueur,



8) Un exemple de procédure complète

main([A]) ->
%recuperation de la ligne de commande
Nom_fichier = atom_to_list(A),
Tailleoctet= fileinfo:file_size_and_type(Nom_fichier),
Taille= round (Tailleoctet/ ?GO2OCTET * 100)/100,
io:format("Taille du fichier:~p Go~n",[Taille]),
io:format("Trunk ~p Octets~n",[?TRUNK]),
%preparation du nombre de morceaux et de leur taille
Morceaux= fileinfo:decoupe(Tailleoctet,round(?TRUNK),0,0,"eric%%.mkv",[]),
io:format("Result ~p~n",[Morceaux]),
% lancement des decoupages
launcher(Morceaux,Nom_fichier). % lancement processus qui vont decouper le fichier

% init:stop().
%% donc le programme ne s arrete jamais !!

9) détail du lanceur


launcher([],Nom) -> ok;
launcher([H|Reste],Nom) -> Nom_segment =H#segment.nom ,
Debut_segment =H#segment.debut,
Longueur_segment=H#segment.longueur,
io:format("Lancement de ~p debut ~p longueur ~p~n",[Nom_segment,Debut_segment,Longueur_segment]),
spawn(fileinfo,create_segment,[Nom,Nom_segment,Debut_segment,Longueur_segment]),
launcher(Reste,Nom).



La procédure est récursive, la premiere ligne est le cas trivial :
launcher([],Nom) -> ok;
La liste est vide , je n'ai plus rien à lancer.




10) Les pages d'aide.

erl -man NOM_De_LA_PAGE

exemples :
erl -man Erlang (% donne le détails des BIFS Build In Function)
erl -man io
erl -man file

Il reste à voir :
-Le mode debug
-L'écriture d'un vrai superviseur
-Le dalogue entre le superviseur et les processus travailleurs

Aucun commentaire: