\documentclass{tp-caml}

\tp{
  title=Premiers pas en Caml,
  number=Premier,
  date=Vendredi 7 janvier 2011,
  class=HX4 \& HX1
}

\begin{document}

\begin{abstract}
Vous avez déjà quelques notions de Caml, il vous faut maintenant passer à la pratique. Et pour cela choisir et maîtriser une interface. Une bonne solution, quelque soit le système d'exploitation, c'est Emacs avec le tuareg mode. Cependant, pour ceux qui ne connaissent pas déjà Emacs et qui veulent aller à la simplicité, il est plus facile de programmer en choisissant une autre interface. Les utilisateurs de mac peuvent s'orienter vers camlx et ceux de windows vers le notepad avec l'interface par défaut de caml sous windows. À tout moment, n'hésitez pas à me poser des questions.
\end{abstract}

\begin{corpus}

\section{Préliminaires}

Pour vous familiariser avec l'interface, vous allez commencer par des programmes simples. Les solutions aux questions suivantes tiennent en une ligne.

\subsection{Calculs}
\begin{exo}
Faites faire à Caml les calculs suivants : $1+1$, $2*3$, "bonjour" concaténé avec " le monde !". (Les guillemets ne sont là que pour délimiter les chaînes.) Comparez pour l'ordre < de caml : "hx1","hx4", "HX4" et "HX1", true avec false.
\end{exo}
\begin{solc}
1+1;;2*3;;
"bonjour"^" le monde!";;
"hx4">"hx1";;"hx1">"HX4";;"HX4">"HX1";;
false<true;;
\end{solc}

\begin{exo}
Corrigez les expressions suivantes pour qu'elles aient un sens et soient correctes et effectuez les: $2.3^{42}$, $6.4*6$, "24"+"18".
\end{exo}
\begin{solc}
2.3**42.0;;
2*3;;
24+18;; ou "24"^"18";;
\end{solc}

\subsection{Affichage}

Pour l'affichage on utilise les fonctions : \begin{prototype}
	print_type : type -> unit  
  \end{prototype}
  où type est \textit{int, string, float, char}

\begin{exo}\textbf{Hello world!}

Faites un programme qui affiche : Hello world!  
\end{exo}

\begin{solc}
print_string "Hello world!";;
\end{solc}

\begin{exo}
Faites un programme qui affiche le résultat des expressions suivantes : $2+3$, $2.0^{42.0}$.
\end{exo}
\begin{solc}
print_int (2+3);;
print_float (2.0**42.0);;
\end{solc}

\section{Variables et fonctions}

\subsection{Variables}
En Caml on peut définir des variables dites \textit{globales} de la manière suivante : 
\begin{caml}
let x = expr
\end{caml}	

ou \textit{locales} de la manière suivante : 
\begin{caml} 
let x = expr1 in expr2
\end{caml}

mais de cette seconde manière $x$ ne vaudra $expr1$ que dans $expr2$. Après il vaudra ce qu'il valait avant et donc rien s'il ne valait rien avant. La première expression n'a ni type ni valeur tandis que la seconde a le type et la valeur de $expr2$.

Par exemple:
\begin{caml}
let x = 3 ;;
let y = 2 ;;
print_int (x*x*y) ;;
\end{caml}
affiche 18 et
\begin{caml}
let x = 42 in
  (let y = x*x in
    y+1)
;;
\end{caml}
nous renvoie \textit{- : int = 1765}

\begin{exod}
Sans recopier le code dans caml, devinez-vous ce que renvoie :
\begin{caml}
let x = 7 in
  let x = 2 in
    (let x = x*x in
      x+1)+x
;;
\end{caml}
?
\end{exod}
\begin{sol}
(4+1)+2 donc 7
\end{sol}

\begin{exo}
Faites le calcul suivant en utilisant des variables pour ne pas recopier les termes qui apparaissent plusieurs fois et simplifier la lecture (mais sans simplifier l'expression):
$$\dfrac{\dfrac{(23*34)^2}{8}+6*7*23*34*9}{3}+(6*7)^2$$
\end{exo}
\begin{solc}
let a = 23*34 in
  let b = 6*7 in
    let num = a*a/8+b*a*9 in
      num/3+b*b
\end{solc}

\subsection{fonctions}
En Caml, il n'y a pas de vraie différence entre une fonction (ce qui est déclaré par un $proc$ en Maple) et un type de base \textit{(int, string, ...)}. C'est donc naturellement que l'on déclare les fonctions avec des \textbf{let}. La définition d'une fonction se fait de la façon suivante :
\begin{caml}
let nom_fonction arg1 arg2 ... argn = expr
\end{caml}
ou, si l'on veut faire une fonction locale :
\begin{caml}
let nom_fonction arg1 arg2 ... argn = expr in expr2
\end{caml}

Ainsi si l'on veut faire une fonction qui donne le carré d'un entier on écrit
\begin{caml}
let carre x = x*x ;;
\end{caml}

\begin{exo}
Écrivez une fonction qui calcule le produit de deux nombres entiers, puis de deux nombres réels.
\end{exo}
\begin{solc}
let int_prod x y = x*y ;;
let float_prod x y = x*.y ;;
\end{solc}

\begin{exo}
Écrivez une fonction $f$ qui, étant donné des $float$ $x$ et $y$, renvoie $\dfrac{y/x+x}{2}$.
\end{exo}
\begin{solc}
let f x y = ((y/.x)+.x)/.2.0 ;;
\end{solc}

\paragraph{Note} En caml, il existe la structure \textbf{if}, \textbf{then}, \textbf{else} qu'on utilise de la facon suivante : 
\begin{caml}
if condition
then expr1
else expr2
\end{caml}
(la même qu'en Maple) et où $expr1$ et $expr2$ doivent avoir le même type qui sera le type de toute l'expression. $condition$ doit être un booléen.

\begin{exo}
Écrivez une fonction fabs qui renvoie la valeur absolue d'un $float$.
\end{exo}
\begin{solc}
let fabs a = 
  if a < 0.
  then -.a
  else a
;;
\end{solc}

\begin{exo}
Programmez la fonction 
\begin{prototype}
	print_bool : bool -> unit
\end{prototype}
qui affiche "True" ou "False" selon la valeur du booléen donné en paramètre. Affichez le résultat du calcul $20.0^{30.0}>30.0^{20.0}$.
\end{exo}
\begin{solc}
let print_bool b = print_string (if b then "True\n" else "False\n");;
print_bool (20.0**30.0>30.0**20.0);;
\end{solc}

\subsection{le mot clé \textbf{rec}}
Il arrive parfois que l'on veuille définir quelque chose en fonction de lui même par exemple une suite récursive ($u_{n+1} = f(u_n)$). Aussi caml permet de le faire avec l'aide du mot clé \textbf{rec}. Pour cela on rajoute \textbf{rec} juste après \textbf{let} dans un définition. Par exemple, la factorielle est définie comme étant $1$ pour $0!$ et $n*((n-1)!)$ sinon. On écrit donc en caml :
\begin{caml}
let rec factorielle n = 
 if n = 0
 then 1
 else n*(factorielle (n-1)) ;;
\end{caml}

\begin{exo}
Faites une fonction qui prend en argument un entier $n$ et un float $y$ et qui donne le {n\ieme}  terme de la suite récursive définie à partir de la fonction $x \mapsto f(x,y)$ de la question 8 et d'un $u_0 = 1$. Vers quoi converge cette suite à $y$ fixé ? 
\end{exo}

\begin{sol}
Cette suite converge vers $\sqrt{y}$
\begin{caml}
let rec terme y n = 
  if n = 0 
  then 1.
  else f(terme y (n-1))
;;
\end{caml}
\end{sol}

\begin{exo}
Écrivez une fonction récursive qui prend en argument deux entiers : $p,n \geq 1$ et qui renvoie le plus grand entier $k \leq n$ tel que $p$ mod $k = 0$. En déduire une fonction
\begin{prototype}
	est_premier : int -> bool
\end{prototype}
qui teste la primalité de son argument.
\end{exo}

\begin{solc}
let rec diviseur p n = 
  if p mod n = 0 
  then n
  else diviseur p (n-1) 
;;

let est_premier p = 
  p>1 && (diviseur p (p-1) = 1)
;;
\end{solc}


\begin{exo}
Écrivez un programme qui étant donné une fonction continue $f$ et deux abscisses $a$ et $b$ tels que $f(a) \leq 0$, $f(b) \geq 0 $ et $\varepsilon $ (tous des $float$), revoie $x$ tel que $|f(x)| \leq \varepsilon$. La précision du float peut vous poser un problème pour certains couples $f,\varepsilon$ mais ce n'est pas grave car votre fonction ne sera utilisée que dans des cas raisonnables. (Cependant, l'élégance voudrait que vous programmiez une fonction qui termine, quitte à s'autoriser un petit écart à la condition $|f(x)| \leq \varepsilon$.)
\end{exo}
\begin{solc}
let rec dichotomie f a b epsilon = 
  let mil = (a+.b)/.2. in
  if fabs (f mil) < epsilon || a = mil || b = mil
  then mil
  else    
    if (f mil) < 0.0    
    then dichotomie f mil b epsilon
    else dichotomie f a mil epsilon
;;
\end{solc}

\begin{exod}
Écrivez une fonction
\begin{prototype}
      racine_nieme : int -> float -> float
\end{prototype}
qui, étant donné n et x, renvoie ${}^n{\sqrt{x}}$. Vous ne devez pas utiliser de conversions $int$ vers $float$ (ou l'inverse) dans cette question. Pensez à ré-utiliser les questions précédentes.
\end{exod}
\begin{solc}
let racine_nieme n x = 
  let poly y = 
  	let rec foo n =
  	  if n = 0
  	  then 1.
  	  else y*.(foo (n-1)) 
  	in
  	(foo n)-.x in
  dichotomie poly 0. (x+.1.) 0.
;;
\end{solc}

\begin{exod}
Écrivez les fonctions de conversions des $float$ vers les $int$ et réciproquement. Si votre solution est lente (si votre fonction tourne plus d'un millième de seconde) sur les entrées 1e09 ou 1000 000 000, recodez-les plus de manière plus rapide.
\end{exod}
\begin{solc}
let rec itof i =
  if i < 0
  then  (-1.0)*.itof (-i)
  else
    if i = 0 
    then 0.0
    else
      (if i mod 2 = 1 
       then 1.0
      else 0.0)+.2.*.(itof (i/2))
;;

let ftoi f =
  let rec foo f = 
    if f < 0.5 
    then (0,f)
    else
      let (ss,sf) = foo (f/.2.) in
      if  sf<0.5
      then (ss*2,sf*.2.)
      else (ss*2+1,(sf-.0.5)*.2.)
  in
  (if f < 0.0 then (-1) else 1)*(fst (foo (fabs f)))
;;
\end{solc}
\paragraph{Note:} les fonctions de la bibliothèque standard sont de la forme
\begin{prototype}
	type1_of_type2
\end{prototype}
mais utilisent quand c'est possible des instructions processeurs elles sont donc quasi-instantanées.
$\blacksquare$\\
\\
\\
\\
\\
\\
\\
\\
\\
\\

\end{corpus}


\end{document}



%%% Local Variables: 
%%% mode: latex
%%% TeX-master: t
%%% End: 
	
